mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 07:06:35 +09:00
Merge remote-tracking branch 'upstream/master' into lead-in-fixes
This commit is contained in:
154
osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs
Normal file
154
osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Edit;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps
|
||||
{
|
||||
[TestFixture]
|
||||
public class EditorBeatmapTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests that the addition event is correctly invoked after a hitobject is added.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestHitObjectAddEvent()
|
||||
{
|
||||
var editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap());
|
||||
|
||||
HitObject addedObject = null;
|
||||
editorBeatmap.HitObjectAdded += h => addedObject = h;
|
||||
|
||||
var hitCircle = new HitCircle();
|
||||
|
||||
editorBeatmap.Add(hitCircle);
|
||||
Assert.That(addedObject, Is.EqualTo(hitCircle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that the removal event is correctly invoked after a hitobject is removed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void HitObjectRemoveEvent()
|
||||
{
|
||||
var hitCircle = new HitCircle();
|
||||
var editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap { HitObjects = { hitCircle } });
|
||||
|
||||
HitObject removedObject = null;
|
||||
editorBeatmap.HitObjectRemoved += h => removedObject = h;
|
||||
|
||||
editorBeatmap.Remove(hitCircle);
|
||||
Assert.That(removedObject, Is.EqualTo(hitCircle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that the changed event is correctly invoked after the start time of a hitobject is changed.
|
||||
/// This tests for hitobjects which were already present before the editor beatmap was constructed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestInitialHitObjectStartTimeChangeEvent()
|
||||
{
|
||||
var hitCircle = new HitCircle();
|
||||
var editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap { HitObjects = { hitCircle } });
|
||||
|
||||
HitObject changedObject = null;
|
||||
editorBeatmap.StartTimeChanged += h => changedObject = h;
|
||||
|
||||
hitCircle.StartTime = 1000;
|
||||
Assert.That(changedObject, Is.EqualTo(hitCircle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that the changed event is correctly invoked after the start time of a hitobject is changed.
|
||||
/// This tests for hitobjects which were added to an existing editor beatmap.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddedHitObjectStartTimeChangeEvent()
|
||||
{
|
||||
var editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap());
|
||||
|
||||
HitObject changedObject = null;
|
||||
editorBeatmap.StartTimeChanged += h => changedObject = h;
|
||||
|
||||
var hitCircle = new HitCircle();
|
||||
|
||||
editorBeatmap.Add(hitCircle);
|
||||
Assert.That(changedObject, Is.Null);
|
||||
|
||||
hitCircle.StartTime = 1000;
|
||||
Assert.That(changedObject, Is.EqualTo(hitCircle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that the channged event is not invoked after a hitobject is removed from the beatmap/
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRemovedHitObjectStartTimeChangeEvent()
|
||||
{
|
||||
var hitCircle = new HitCircle();
|
||||
var editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap { HitObjects = { hitCircle } });
|
||||
|
||||
HitObject changedObject = null;
|
||||
editorBeatmap.StartTimeChanged += h => changedObject = h;
|
||||
|
||||
editorBeatmap.Remove(hitCircle);
|
||||
Assert.That(changedObject, Is.Null);
|
||||
|
||||
hitCircle.StartTime = 1000;
|
||||
Assert.That(changedObject, Is.Null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that an added hitobject is correctly inserted to preserve the sorting order of the beatmap.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddHitObjectInMiddle()
|
||||
{
|
||||
var editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap
|
||||
{
|
||||
HitObjects =
|
||||
{
|
||||
new HitCircle(),
|
||||
new HitCircle { StartTime = 1000 },
|
||||
new HitCircle { StartTime = 1000 },
|
||||
new HitCircle { StartTime = 2000 },
|
||||
}
|
||||
});
|
||||
|
||||
var hitCircle = new HitCircle { StartTime = 1000 };
|
||||
editorBeatmap.Add(hitCircle);
|
||||
Assert.That(editorBeatmap.HitObjects.Count(h => h == hitCircle), Is.EqualTo(1));
|
||||
Assert.That(editorBeatmap.HitObjects.IndexOf(hitCircle), Is.EqualTo(3));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that the beatmap remains correctly sorted after the start time of a hitobject is changed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestResortWhenStartTimeChanged()
|
||||
{
|
||||
var hitCircle = new HitCircle { StartTime = 1000 };
|
||||
var editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap
|
||||
{
|
||||
HitObjects =
|
||||
{
|
||||
new HitCircle(),
|
||||
new HitCircle { StartTime = 1000 },
|
||||
new HitCircle { StartTime = 1000 },
|
||||
hitCircle,
|
||||
new HitCircle { StartTime = 2000 },
|
||||
}
|
||||
});
|
||||
|
||||
hitCircle.StartTime = 0;
|
||||
Assert.That(editorBeatmap.HitObjects.Count(h => h == hitCircle), Is.EqualTo(1));
|
||||
Assert.That(editorBeatmap.HitObjects.IndexOf(hitCircle), Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -30,13 +31,9 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
public void TestDecodeBeatmapVersion()
|
||||
{
|
||||
using (var resStream = TestResources.OpenResource("beatmap-version.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var decoder = Decoder.GetDecoder<Beatmap>(stream);
|
||||
|
||||
stream.BaseStream.Position = 0;
|
||||
stream.DiscardBufferedData();
|
||||
|
||||
var working = new TestWorkingBeatmap(decoder.Decode(stream));
|
||||
|
||||
Assert.AreEqual(6, working.BeatmapInfo.BeatmapVersion);
|
||||
@ -51,7 +48,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
var beatmapInfo = beatmap.BeatmapInfo;
|
||||
@ -75,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmapInfo = decoder.Decode(stream).BeatmapInfo;
|
||||
|
||||
@ -101,7 +98,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
var beatmapInfo = beatmap.BeatmapInfo;
|
||||
@ -126,7 +123,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty;
|
||||
|
||||
@ -145,7 +142,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
var metadata = beatmap.Metadata;
|
||||
@ -164,15 +161,15 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
var controlPoints = beatmap.ControlPointInfo;
|
||||
|
||||
Assert.AreEqual(4, controlPoints.TimingPoints.Count);
|
||||
Assert.AreEqual(42, controlPoints.DifficultyPoints.Count);
|
||||
Assert.AreEqual(42, controlPoints.SamplePoints.Count);
|
||||
Assert.AreEqual(42, controlPoints.EffectPoints.Count);
|
||||
Assert.AreEqual(5, controlPoints.DifficultyPoints.Count);
|
||||
Assert.AreEqual(34, controlPoints.SamplePoints.Count);
|
||||
Assert.AreEqual(8, controlPoints.EffectPoints.Count);
|
||||
|
||||
var timingPoint = controlPoints.TimingPointAt(0);
|
||||
Assert.AreEqual(956, timingPoint.Time);
|
||||
@ -194,7 +191,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual(1.0, difficultyPoint.SpeedMultiplier);
|
||||
|
||||
difficultyPoint = controlPoints.DifficultyPointAt(48428);
|
||||
Assert.AreEqual(48428, difficultyPoint.Time);
|
||||
Assert.AreEqual(0, difficultyPoint.Time);
|
||||
Assert.AreEqual(1.0, difficultyPoint.SpeedMultiplier);
|
||||
|
||||
difficultyPoint = controlPoints.DifficultyPointAt(116999);
|
||||
@ -227,7 +224,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
||||
|
||||
effectPoint = controlPoints.EffectPointAt(119637);
|
||||
Assert.AreEqual(119637, effectPoint.Time);
|
||||
Assert.AreEqual(95901, effectPoint.Time);
|
||||
Assert.IsFalse(effectPoint.KiaiMode);
|
||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
||||
}
|
||||
@ -239,7 +236,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("overlapping-control-points.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var controlPoints = decoder.Decode(stream).ControlPointInfo;
|
||||
|
||||
@ -265,13 +262,28 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTimingPointResetsSpeedMultiplier()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("timingpoint-speedmultiplier-reset.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var controlPoints = decoder.Decode(stream).ControlPointInfo;
|
||||
|
||||
Assert.That(controlPoints.DifficultyPointAt(0).SpeedMultiplier, Is.EqualTo(0.5).Within(0.1));
|
||||
Assert.That(controlPoints.DifficultyPointAt(2000).SpeedMultiplier, Is.EqualTo(1).Within(0.1));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeBeatmapColours()
|
||||
{
|
||||
var decoder = new LegacySkinDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var comboColors = decoder.Decode(stream).ComboColours;
|
||||
|
||||
@ -297,7 +309,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
|
||||
@ -320,7 +332,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
|
||||
@ -343,7 +355,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
@ -354,14 +366,31 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.IsNotNull(curveData);
|
||||
Assert.AreEqual(new Vector2(192, 168), positionData.Position);
|
||||
Assert.AreEqual(956, hitObjects[0].StartTime);
|
||||
Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
|
||||
Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL));
|
||||
|
||||
positionData = hitObjects[1] as IHasPosition;
|
||||
|
||||
Assert.IsNotNull(positionData);
|
||||
Assert.AreEqual(new Vector2(304, 56), positionData.Position);
|
||||
Assert.AreEqual(1285, hitObjects[1].StartTime);
|
||||
Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
|
||||
Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeControlPointDifficultyChange()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("controlpoint-difficulty-multiplier.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var controlPointInfo = decoder.Decode(stream).ControlPointInfo;
|
||||
|
||||
Assert.That(controlPointInfo.DifficultyPointAt(5).SpeedMultiplier, Is.EqualTo(1));
|
||||
Assert.That(controlPointInfo.DifficultyPointAt(1000).SpeedMultiplier, Is.EqualTo(10));
|
||||
Assert.That(controlPointInfo.DifficultyPointAt(2000).SpeedMultiplier, Is.EqualTo(1.8518518518518519d));
|
||||
Assert.That(controlPointInfo.DifficultyPointAt(3000).SpeedMultiplier, Is.EqualTo(0.5));
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,7 +400,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("controlpoint-custom-samplebank.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
@ -384,7 +413,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual("soft-hitnormal8", getTestableSampleInfo(hitObjects[4]).LookupNames.First());
|
||||
}
|
||||
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -393,7 +422,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("hitobject-custom-samplebank.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
@ -402,7 +431,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual("normal-hitnormal3", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
|
||||
}
|
||||
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -411,7 +440,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("hitobject-file-samples.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
@ -422,7 +451,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual(70, getTestableSampleInfo(hitObjects[3]).Volume);
|
||||
}
|
||||
|
||||
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -431,41 +460,41 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("slider-samples.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
var slider1 = (ConvertSlider)hitObjects[0];
|
||||
|
||||
Assert.AreEqual(1, slider1.NodeSamples[0].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name);
|
||||
Assert.AreEqual(1, slider1.NodeSamples[1].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name);
|
||||
Assert.AreEqual(1, slider1.NodeSamples[2].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name);
|
||||
|
||||
var slider2 = (ConvertSlider)hitObjects[1];
|
||||
|
||||
Assert.AreEqual(2, slider2.NodeSamples[0].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name);
|
||||
Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name);
|
||||
Assert.AreEqual(2, slider2.NodeSamples[1].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name);
|
||||
Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name);
|
||||
Assert.AreEqual(2, slider2.NodeSamples[2].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name);
|
||||
Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name);
|
||||
|
||||
var slider3 = (ConvertSlider)hitObjects[2];
|
||||
|
||||
Assert.AreEqual(2, slider3.NodeSamples[0].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name);
|
||||
Assert.AreEqual(SampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name);
|
||||
Assert.AreEqual(1, slider3.NodeSamples[1].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name);
|
||||
Assert.AreEqual(2, slider3.NodeSamples[2].Count);
|
||||
Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name);
|
||||
Assert.AreEqual(SampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name);
|
||||
Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,12 +504,146 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("hitobject-no-addition-bank.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||
|
||||
Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidEventStillPasses()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var badResStream = TestResources.OpenResource("invalid-events.osu"))
|
||||
using (var badStream = new LineBufferedReader(badResStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder.Decode(badStream));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFallbackDecoderForCorruptedHeader()
|
||||
{
|
||||
Decoder<Beatmap> decoder = null;
|
||||
Beatmap beatmap = null;
|
||||
|
||||
using (var resStream = TestResources.OpenResource("corrupted-header.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder<Beatmap>(stream));
|
||||
Assert.IsInstanceOf<LegacyBeatmapDecoder>(decoder);
|
||||
Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream));
|
||||
Assert.IsNotNull(beatmap);
|
||||
Assert.AreEqual("Beatmap with corrupted header", beatmap.Metadata.Title);
|
||||
Assert.AreEqual("Evil Hacker", beatmap.Metadata.AuthorString);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFallbackDecoderForMissingHeader()
|
||||
{
|
||||
Decoder<Beatmap> decoder = null;
|
||||
Beatmap beatmap = null;
|
||||
|
||||
using (var resStream = TestResources.OpenResource("missing-header.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder<Beatmap>(stream));
|
||||
Assert.IsInstanceOf<LegacyBeatmapDecoder>(decoder);
|
||||
Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream));
|
||||
Assert.IsNotNull(beatmap);
|
||||
Assert.AreEqual("Beatmap with no header", beatmap.Metadata.Title);
|
||||
Assert.AreEqual("Incredibly Evil Hacker", beatmap.Metadata.AuthorString);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeFileWithEmptyLinesAtStart()
|
||||
{
|
||||
Decoder<Beatmap> decoder = null;
|
||||
Beatmap beatmap = null;
|
||||
|
||||
using (var resStream = TestResources.OpenResource("empty-lines-at-start.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder<Beatmap>(stream));
|
||||
Assert.IsInstanceOf<LegacyBeatmapDecoder>(decoder);
|
||||
Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream));
|
||||
Assert.IsNotNull(beatmap);
|
||||
Assert.AreEqual("Empty lines at start", beatmap.Metadata.Title);
|
||||
Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.AuthorString);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeFileWithEmptyLinesAndNoHeader()
|
||||
{
|
||||
Decoder<Beatmap> decoder = null;
|
||||
Beatmap beatmap = null;
|
||||
|
||||
using (var resStream = TestResources.OpenResource("empty-line-instead-of-header.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder<Beatmap>(stream));
|
||||
Assert.IsInstanceOf<LegacyBeatmapDecoder>(decoder);
|
||||
Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream));
|
||||
Assert.IsNotNull(beatmap);
|
||||
Assert.AreEqual("The dog ate the file header", beatmap.Metadata.Title);
|
||||
Assert.AreEqual("Why does this keep happening", beatmap.Metadata.AuthorString);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeFileWithContentImmediatelyAfterHeader()
|
||||
{
|
||||
Decoder<Beatmap> decoder = null;
|
||||
Beatmap beatmap = null;
|
||||
|
||||
using (var resStream = TestResources.OpenResource("no-empty-line-after-header.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder<Beatmap>(stream));
|
||||
Assert.IsInstanceOf<LegacyBeatmapDecoder>(decoder);
|
||||
Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream));
|
||||
Assert.IsNotNull(beatmap);
|
||||
Assert.AreEqual("No empty line delimiting header from contents", beatmap.Metadata.Title);
|
||||
Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.AuthorString);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeEmptyFile()
|
||||
{
|
||||
using (var resStream = new MemoryStream())
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.Throws<IOException>(() => Decoder.GetDecoder<Beatmap>(stream));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAllowFallbackDecoderOverwrite()
|
||||
{
|
||||
Decoder<Beatmap> decoder = null;
|
||||
|
||||
using (var resStream = TestResources.OpenResource("corrupted-header.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder<Beatmap>(stream));
|
||||
Assert.IsInstanceOf<LegacyBeatmapDecoder>(decoder);
|
||||
}
|
||||
|
||||
Assert.DoesNotThrow(LegacyDifficultyCalculatorBeatmapDecoder.Register);
|
||||
|
||||
using (var resStream = TestResources.OpenResource("corrupted-header.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder<Beatmap>(stream));
|
||||
Assert.IsInstanceOf<LegacyDifficultyCalculatorBeatmapDecoder>(decoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.Formats
|
||||
@ -18,7 +18,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LineLoggingDecoder(14);
|
||||
|
||||
using (var resStream = TestResources.OpenResource("comments.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
decoder.Decode(stream);
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osuTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Storyboards;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyStoryboardDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
|
||||
int spriteCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSprite));
|
||||
int animationCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardAnimation));
|
||||
int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSample));
|
||||
int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSampleInfo));
|
||||
|
||||
Assert.AreEqual(15, spriteCount);
|
||||
Assert.AreEqual(1, animationCount);
|
||||
@ -94,7 +94,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var decoder = new LegacyStoryboardDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("variable-with-suffix.osb"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
|
@ -8,9 +8,10 @@ using NUnit.Framework;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
|
||||
@ -101,14 +102,14 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.IsNotNull(curveData);
|
||||
Assert.AreEqual(new Vector2(192, 168), positionData.Position);
|
||||
Assert.AreEqual(956, beatmap.HitObjects[0].StartTime);
|
||||
Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
|
||||
Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL));
|
||||
|
||||
positionData = beatmap.HitObjects[1] as IHasPosition;
|
||||
|
||||
Assert.IsNotNull(positionData);
|
||||
Assert.AreEqual(new Vector2(304, 56), positionData.Position);
|
||||
Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime);
|
||||
Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
|
||||
Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP));
|
||||
}
|
||||
|
||||
[TestCase(normal)]
|
||||
@ -148,13 +149,13 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
private Beatmap decode(string filename, out Beatmap jsonDecoded)
|
||||
{
|
||||
using (var stream = TestResources.OpenResource(filename))
|
||||
using (var sr = new StreamReader(stream))
|
||||
using (var sr = new LineBufferedReader(stream))
|
||||
{
|
||||
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
using (var sw = new StreamWriter(ms))
|
||||
using (var sr2 = new StreamReader(ms))
|
||||
using (var sr2 = new LineBufferedReader(ms))
|
||||
{
|
||||
sw.Write(legacyDecoded.Serialize());
|
||||
sw.Flush();
|
||||
|
@ -11,9 +11,14 @@ using NUnit.Framework;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.IPC;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Tests.Resources;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers.Zip;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
@ -21,14 +26,14 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
public class ImportBeatmapTest
|
||||
{
|
||||
[Test]
|
||||
public void TestImportWhenClosed()
|
||||
public async Task TestImportWhenClosed()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWhenClosed"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenClosed)))
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadOszIntoOsu(loadOsu(host));
|
||||
await LoadOszIntoOsu(loadOsu(host));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -38,16 +43,16 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportThenDelete()
|
||||
public async Task TestImportThenDelete()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenDelete"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDelete)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var imported = LoadOszIntoOsu(osu);
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
|
||||
deleteBeatmapSet(imported, osu);
|
||||
}
|
||||
@ -59,26 +64,24 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportThenImport()
|
||||
public async Task TestImportThenImport()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenImport"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImport)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var imported = LoadOszIntoOsu(osu);
|
||||
var importedSecondTime = LoadOszIntoOsu(osu);
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
var importedSecondTime = await LoadOszIntoOsu(osu);
|
||||
|
||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
||||
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||
checkBeatmapSetCount(osu, 1);
|
||||
checkSingleReferencedFileCount(osu, 18);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -88,34 +91,87 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRollbackOnFailure()
|
||||
public async Task TestImportCorruptThenImport()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestRollbackOnFailure"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportCorruptThenImport)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
|
||||
var firstFile = imported.Files.First();
|
||||
|
||||
var files = osu.Dependencies.Get<FileStore>();
|
||||
|
||||
long originalLength;
|
||||
using (var stream = files.Storage.GetStream(firstFile.FileInfo.StoragePath))
|
||||
originalLength = stream.Length;
|
||||
|
||||
using (var stream = files.Storage.GetStream(firstFile.FileInfo.StoragePath, FileAccess.Write, FileMode.Create))
|
||||
stream.WriteByte(0);
|
||||
|
||||
var importedSecondTime = await LoadOszIntoOsu(osu);
|
||||
|
||||
using (var stream = files.Storage.GetStream(firstFile.FileInfo.StoragePath))
|
||||
Assert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import");
|
||||
|
||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
||||
|
||||
checkBeatmapSetCount(osu, 1);
|
||||
checkSingleReferencedFileCount(osu, 18);
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestRollbackOnFailure()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestRollbackOnFailure)))
|
||||
{
|
||||
try
|
||||
{
|
||||
int itemAddRemoveFireCount = 0;
|
||||
int loggedExceptionCount = 0;
|
||||
|
||||
Logger.NewEntry += l =>
|
||||
{
|
||||
if (l.Target == LoggingTarget.Database && l.Exception != null)
|
||||
Interlocked.Increment(ref loggedExceptionCount);
|
||||
};
|
||||
|
||||
var osu = loadOsu(host);
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
int fireCount = 0;
|
||||
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
manager.ItemAdded += (_, __) => fireCount++;
|
||||
manager.ItemRemoved += _ => fireCount++;
|
||||
manager.ItemAdded += _ => Interlocked.Increment(ref itemAddRemoveFireCount);
|
||||
manager.ItemRemoved += _ => Interlocked.Increment(ref itemAddRemoveFireCount);
|
||||
|
||||
var imported = LoadOszIntoOsu(osu);
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
|
||||
Assert.AreEqual(0, fireCount -= 1);
|
||||
Assert.AreEqual(0, itemAddRemoveFireCount -= 1);
|
||||
|
||||
imported.Hash += "-changed";
|
||||
manager.Update(imported);
|
||||
|
||||
Assert.AreEqual(0, fireCount -= 2);
|
||||
Assert.AreEqual(0, itemAddRemoveFireCount -= 2);
|
||||
|
||||
checkBeatmapSetCount(osu, 1);
|
||||
checkBeatmapCount(osu, 12);
|
||||
checkSingleReferencedFileCount(osu, 18);
|
||||
|
||||
var breakTemp = TestResources.GetTestBeatmapForImport();
|
||||
|
||||
MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 });
|
||||
MemoryStream brokenOsu = new MemoryStream();
|
||||
MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp));
|
||||
|
||||
File.Delete(breakTemp);
|
||||
@ -124,22 +180,27 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
using (var zip = ZipArchive.Open(brokenOsz))
|
||||
{
|
||||
zip.AddEntry("broken.osu", brokenOsu, false);
|
||||
zip.SaveTo(outStream, SharpCompress.Common.CompressionType.Deflate);
|
||||
zip.SaveTo(outStream, CompressionType.Deflate);
|
||||
}
|
||||
|
||||
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||
Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count);
|
||||
|
||||
// this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu.
|
||||
manager.Import(breakTemp);
|
||||
try
|
||||
{
|
||||
await manager.Import(breakTemp);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
// no events should be fired in the case of a rollback.
|
||||
Assert.AreEqual(0, fireCount);
|
||||
Assert.AreEqual(0, itemAddRemoveFireCount);
|
||||
|
||||
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||
Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count);
|
||||
checkBeatmapSetCount(osu, 1);
|
||||
checkBeatmapCount(osu, 12);
|
||||
|
||||
checkSingleReferencedFileCount(osu, 18);
|
||||
|
||||
Assert.AreEqual(1, loggedExceptionCount);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -149,29 +210,28 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportThenImportDifferentHash()
|
||||
public async Task TestImportThenImportDifferentHash()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenImportDifferentHash"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenImportDifferentHash)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
var imported = LoadOszIntoOsu(osu);
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
|
||||
imported.Hash += "-changed";
|
||||
manager.Update(imported);
|
||||
|
||||
var importedSecondTime = LoadOszIntoOsu(osu);
|
||||
var importedSecondTime = await LoadOszIntoOsu(osu);
|
||||
|
||||
Assert.IsTrue(imported.ID != importedSecondTime.ID);
|
||||
Assert.IsTrue(imported.Beatmaps.First().ID < importedSecondTime.Beatmaps.First().ID);
|
||||
|
||||
// only one beatmap will exist as the online set ID matched, causing purging of the first import.
|
||||
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||
checkBeatmapSetCount(osu, 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -181,20 +241,20 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportThenDeleteThenImport()
|
||||
public async Task TestImportThenDeleteThenImport()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenDeleteThenImport"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportThenDeleteThenImport)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var imported = LoadOszIntoOsu(osu);
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
|
||||
deleteBeatmapSet(imported, osu);
|
||||
|
||||
var importedSecondTime = LoadOszIntoOsu(osu);
|
||||
var importedSecondTime = await LoadOszIntoOsu(osu);
|
||||
|
||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||
@ -209,16 +269,16 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
||||
public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"TestImportThenDeleteThenImport-{set}"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"{nameof(TestImportThenDeleteThenImportWithOnlineIDMismatch)}-{set}"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var imported = LoadOszIntoOsu(osu);
|
||||
var imported = await LoadOszIntoOsu(osu);
|
||||
|
||||
if (set)
|
||||
imported.OnlineBeatmapSetID = 1234;
|
||||
@ -229,7 +289,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
deleteBeatmapSet(imported, osu);
|
||||
|
||||
var importedSecondTime = LoadOszIntoOsu(osu);
|
||||
var importedSecondTime = await LoadOszIntoOsu(osu);
|
||||
|
||||
// check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched)
|
||||
Assert.IsTrue(imported.ID != importedSecondTime.ID);
|
||||
@ -243,10 +303,10 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportWithDuplicateBeatmapIDs()
|
||||
public async Task TestImportWithDuplicateBeatmapIDs()
|
||||
{
|
||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWithDuplicateBeatmapID"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateBeatmapIDs)))
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -284,7 +344,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
var imported = manager.Import(toImport);
|
||||
var imported = await manager.Import(toImport);
|
||||
|
||||
Assert.NotNull(imported);
|
||||
Assert.AreEqual(null, imported.Beatmaps[0].OnlineBeatmapID);
|
||||
@ -330,16 +390,16 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportWhenFileOpen()
|
||||
public async Task TestImportWhenFileOpen()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWhenFileOpen"))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWhenFileOpen)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var temp = TestResources.GetTestBeatmapForImport();
|
||||
using (File.OpenRead(temp))
|
||||
osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
ensureLoaded(osu);
|
||||
File.Delete(temp);
|
||||
Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
|
||||
@ -351,13 +411,154 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
}
|
||||
|
||||
public static BeatmapSetInfo LoadOszIntoOsu(OsuGameBase osu, string path = null)
|
||||
[Test]
|
||||
public async Task TestImportWithDuplicateHashes()
|
||||
{
|
||||
var temp = path ?? TestResources.GetTestBeatmapForImport();
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var temp = TestResources.GetTestBeatmapForImport();
|
||||
|
||||
string extractedFolder = $"{temp}_extracted";
|
||||
Directory.CreateDirectory(extractedFolder);
|
||||
|
||||
try
|
||||
{
|
||||
using (var zip = ZipArchive.Open(temp))
|
||||
zip.WriteToDirectory(extractedFolder);
|
||||
|
||||
using (var zip = ZipArchive.Create())
|
||||
{
|
||||
zip.AddAllFromDirectory(extractedFolder);
|
||||
zip.AddEntry("duplicate.osu", Directory.GetFiles(extractedFolder, "*.osu").First());
|
||||
zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
|
||||
}
|
||||
|
||||
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(extractedFolder, true);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestImportNestedStructure()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var temp = TestResources.GetTestBeatmapForImport();
|
||||
|
||||
string extractedFolder = $"{temp}_extracted";
|
||||
string subfolder = Path.Combine(extractedFolder, "subfolder");
|
||||
|
||||
Directory.CreateDirectory(subfolder);
|
||||
|
||||
try
|
||||
{
|
||||
using (var zip = ZipArchive.Open(temp))
|
||||
zip.WriteToDirectory(subfolder);
|
||||
|
||||
using (var zip = ZipArchive.Create())
|
||||
{
|
||||
zip.AddAllFromDirectory(extractedFolder);
|
||||
zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
|
||||
}
|
||||
|
||||
var imported = await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
|
||||
Assert.IsFalse(imported.Files.Any(f => f.Filename.Contains("subfolder")), "Files contain common subfolder");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(extractedFolder, true);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestImportWithIgnoredDirectoryInArchive()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithIgnoredDirectoryInArchive)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
|
||||
var temp = TestResources.GetTestBeatmapForImport();
|
||||
|
||||
string extractedFolder = $"{temp}_extracted";
|
||||
string dataFolder = Path.Combine(extractedFolder, "actual_data");
|
||||
string resourceForkFolder = Path.Combine(extractedFolder, "__MACOSX");
|
||||
string resourceForkFilePath = Path.Combine(resourceForkFolder, ".extracted");
|
||||
|
||||
Directory.CreateDirectory(dataFolder);
|
||||
Directory.CreateDirectory(resourceForkFolder);
|
||||
|
||||
using (var resourceForkFile = File.CreateText(resourceForkFilePath))
|
||||
{
|
||||
resourceForkFile.WriteLine("adding content so that it's not empty");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var zip = ZipArchive.Open(temp))
|
||||
zip.WriteToDirectory(dataFolder);
|
||||
|
||||
using (var zip = ZipArchive.Create())
|
||||
{
|
||||
zip.AddAllFromDirectory(extractedFolder);
|
||||
zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
|
||||
}
|
||||
|
||||
var imported = await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
|
||||
Assert.IsFalse(imported.Files.Any(f => f.Filename.Contains("__MACOSX")), "Files contain resource fork folder, which should be ignored");
|
||||
Assert.IsFalse(imported.Files.Any(f => f.Filename.Contains("actual_data")), "Files contain common subfolder");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(extractedFolder, true);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
||||
{
|
||||
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
||||
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
manager.Import(temp);
|
||||
await manager.Import(temp);
|
||||
|
||||
var imported = manager.GetAllUsableBeatmapSets();
|
||||
|
||||
@ -373,11 +574,32 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
manager.Delete(imported);
|
||||
|
||||
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 0);
|
||||
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||
checkBeatmapSetCount(osu, 0);
|
||||
checkBeatmapSetCount(osu, 1, true);
|
||||
checkSingleReferencedFileCount(osu, 0);
|
||||
|
||||
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending);
|
||||
}
|
||||
|
||||
private void checkBeatmapSetCount(OsuGameBase osu, int expected, bool includeDeletePending = false)
|
||||
{
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
Assert.AreEqual(expected, includeDeletePending
|
||||
? manager.QueryBeatmapSets(_ => true).ToList().Count
|
||||
: manager.GetAllUsableBeatmapSets().Count);
|
||||
}
|
||||
|
||||
private void checkBeatmapCount(OsuGameBase osu, int expected)
|
||||
{
|
||||
Assert.AreEqual(expected, osu.Dependencies.Get<BeatmapManager>().QueryBeatmaps(_ => true).ToList().Count);
|
||||
}
|
||||
|
||||
private void checkSingleReferencedFileCount(OsuGameBase osu, int expected)
|
||||
{
|
||||
Assert.AreEqual(expected, osu.Dependencies.Get<FileStore>().QueryFiles(f => f.ReferenceCount == 1).Count());
|
||||
}
|
||||
|
||||
private OsuGameBase loadOsu(GameHost host)
|
||||
{
|
||||
var osu = new OsuGameBase();
|
||||
|
125
osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs
Normal file
125
osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs
Normal file
@ -0,0 +1,125 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.IO;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
[TestFixture]
|
||||
public class LineBufferedReaderTest
|
||||
{
|
||||
[Test]
|
||||
public void TestReadLineByLine()
|
||||
{
|
||||
const string contents = "line 1\rline 2\nline 3";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
|
||||
using (var bufferedReader = new LineBufferedReader(stream))
|
||||
{
|
||||
Assert.AreEqual("line 1", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("line 2", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("line 3", bufferedReader.ReadLine());
|
||||
Assert.IsNull(bufferedReader.ReadLine());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPeekLineOnce()
|
||||
{
|
||||
const string contents = "line 1\r\npeek this\nline 3";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
|
||||
using (var bufferedReader = new LineBufferedReader(stream))
|
||||
{
|
||||
Assert.AreEqual("line 1", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("peek this", bufferedReader.PeekLine());
|
||||
Assert.AreEqual("peek this", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("line 3", bufferedReader.ReadLine());
|
||||
Assert.IsNull(bufferedReader.ReadLine());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPeekLineMultipleTimes()
|
||||
{
|
||||
const string contents = "peek this once\nline 2\rpeek this a lot";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
|
||||
using (var bufferedReader = new LineBufferedReader(stream))
|
||||
{
|
||||
Assert.AreEqual("peek this once", bufferedReader.PeekLine());
|
||||
Assert.AreEqual("peek this once", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("line 2", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("peek this a lot", bufferedReader.PeekLine());
|
||||
Assert.AreEqual("peek this a lot", bufferedReader.PeekLine());
|
||||
Assert.AreEqual("peek this a lot", bufferedReader.PeekLine());
|
||||
Assert.AreEqual("peek this a lot", bufferedReader.ReadLine());
|
||||
Assert.IsNull(bufferedReader.ReadLine());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPeekLineAtEndOfStream()
|
||||
{
|
||||
const string contents = "first line\r\nsecond line";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
|
||||
using (var bufferedReader = new LineBufferedReader(stream))
|
||||
{
|
||||
Assert.AreEqual("first line", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("second line", bufferedReader.ReadLine());
|
||||
Assert.IsNull(bufferedReader.PeekLine());
|
||||
Assert.IsNull(bufferedReader.ReadLine());
|
||||
Assert.IsNull(bufferedReader.PeekLine());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPeekReadLineOnEmptyStream()
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
using (var bufferedReader = new LineBufferedReader(stream))
|
||||
{
|
||||
Assert.IsNull(bufferedReader.PeekLine());
|
||||
Assert.IsNull(bufferedReader.ReadLine());
|
||||
Assert.IsNull(bufferedReader.ReadLine());
|
||||
Assert.IsNull(bufferedReader.PeekLine());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReadToEndNoPeeks()
|
||||
{
|
||||
const string contents = "first line\r\nsecond line";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
|
||||
using (var bufferedReader = new LineBufferedReader(stream))
|
||||
{
|
||||
Assert.AreEqual(contents, bufferedReader.ReadToEnd());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReadToEndAfterReadsAndPeeks()
|
||||
{
|
||||
const string contents = "this line is gone\rthis one shouldn't be\r\nthese ones\ndefinitely not";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
|
||||
using (var bufferedReader = new LineBufferedReader(stream))
|
||||
{
|
||||
Assert.AreEqual("this line is gone", bufferedReader.ReadLine());
|
||||
Assert.AreEqual("this one shouldn't be", bufferedReader.PeekLine());
|
||||
|
||||
var endingLines = bufferedReader.ReadToEnd().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
Assert.AreEqual(3, endingLines.Length);
|
||||
Assert.AreEqual("this one shouldn't be", endingLines[0]);
|
||||
Assert.AreEqual("these ones", endingLines[1]);
|
||||
Assert.AreEqual("definitely not", endingLines[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.IO.Archives;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.IO
|
||||
@ -50,7 +51,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
Beatmap beatmap;
|
||||
|
||||
using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
|
||||
using (var stream = new LineBufferedReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
|
||||
beatmap = Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
|
||||
|
||||
var meta = beatmap.Metadata;
|
||||
|
116
osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs
Normal file
116
osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps
|
||||
{
|
||||
[TestFixture]
|
||||
public class SliderEventGenerationTest
|
||||
{
|
||||
private const double start_time = 0;
|
||||
private const double span_duration = 1000;
|
||||
|
||||
[Test]
|
||||
public void TestSingleSpan()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null).ToArray();
|
||||
|
||||
Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head));
|
||||
Assert.That(events[0].Time, Is.EqualTo(start_time));
|
||||
|
||||
Assert.That(events[1].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[1].Time, Is.EqualTo(span_duration / 2));
|
||||
|
||||
Assert.That(events[3].Type, Is.EqualTo(SliderEventType.Tail));
|
||||
Assert.That(events[3].Time, Is.EqualTo(span_duration));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRepeat()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 2, null).ToArray();
|
||||
|
||||
Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head));
|
||||
Assert.That(events[0].Time, Is.EqualTo(start_time));
|
||||
|
||||
Assert.That(events[1].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[1].Time, Is.EqualTo(span_duration / 2));
|
||||
|
||||
Assert.That(events[2].Type, Is.EqualTo(SliderEventType.Repeat));
|
||||
Assert.That(events[2].Time, Is.EqualTo(span_duration));
|
||||
|
||||
Assert.That(events[3].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[3].Time, Is.EqualTo(span_duration + span_duration / 2));
|
||||
|
||||
Assert.That(events[5].Type, Is.EqualTo(SliderEventType.Tail));
|
||||
Assert.That(events[5].Time, Is.EqualTo(2 * span_duration));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNonEvenTicks()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, 300, span_duration, 2, null).ToArray();
|
||||
|
||||
Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head));
|
||||
Assert.That(events[0].Time, Is.EqualTo(start_time));
|
||||
|
||||
Assert.That(events[1].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[1].Time, Is.EqualTo(300));
|
||||
|
||||
Assert.That(events[2].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[2].Time, Is.EqualTo(600));
|
||||
|
||||
Assert.That(events[3].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[3].Time, Is.EqualTo(900));
|
||||
|
||||
Assert.That(events[4].Type, Is.EqualTo(SliderEventType.Repeat));
|
||||
Assert.That(events[4].Time, Is.EqualTo(span_duration));
|
||||
|
||||
Assert.That(events[5].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[5].Time, Is.EqualTo(1100));
|
||||
|
||||
Assert.That(events[6].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[6].Time, Is.EqualTo(1400));
|
||||
|
||||
Assert.That(events[7].Type, Is.EqualTo(SliderEventType.Tick));
|
||||
Assert.That(events[7].Time, Is.EqualTo(1700));
|
||||
|
||||
Assert.That(events[9].Type, Is.EqualTo(SliderEventType.Tail));
|
||||
Assert.That(events[9].Time, Is.EqualTo(2 * span_duration));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLegacyLastTickOffset()
|
||||
{
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, 100).ToArray();
|
||||
|
||||
Assert.That(events[2].Type, Is.EqualTo(SliderEventType.LegacyLastTick));
|
||||
Assert.That(events[2].Time, Is.EqualTo(900));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMinimumTickDistance()
|
||||
{
|
||||
const double velocity = 5;
|
||||
const double min_distance = velocity * 10;
|
||||
|
||||
var events = SliderEventGenerator.Generate(start_time, span_duration, velocity, velocity, span_duration, 2, 0).ToArray();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
int tickIndex = -1;
|
||||
|
||||
while (++tickIndex < events.Length)
|
||||
{
|
||||
if (events[tickIndex].Type != SliderEventType.Tick)
|
||||
continue;
|
||||
|
||||
Assert.That(events[tickIndex].Time, Is.LessThan(span_duration - min_distance).Or.GreaterThan(span_duration + min_distance));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -119,6 +119,53 @@ namespace osu.Game.Tests.Chat
|
||||
Assert.AreEqual(11, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOldFormatLinkWithBalancedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (tricky (one))[https://osu.ppy.sh]!" });
|
||||
|
||||
Assert.AreEqual("This is a tricky (one)!", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(12, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOldFormatLinkWithEscapedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is (another loose bracket \\))[https://osu.ppy.sh]." });
|
||||
|
||||
Assert.AreEqual("This is another loose bracket ).", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(8, result.Links[0].Index);
|
||||
Assert.AreEqual(23, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOldFormatWithBackslashes()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This link (should end with a backslash \\)[https://osu.ppy.sh]." });
|
||||
Assert.AreEqual("This link should end with a backslash \\.", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(29, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOldFormatLinkWithEscapedAndBalancedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (\\)super\\(\\( tricky (one))[https://osu.ppy.sh]!" });
|
||||
|
||||
Assert.AreEqual("This is a )super(( tricky (one)!", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(21, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNewFormatLink()
|
||||
{
|
||||
@ -131,6 +178,42 @@ namespace osu.Game.Tests.Chat
|
||||
Assert.AreEqual(11, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNewFormatLinkWithEscapedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh nasty link with escaped brackets: \\] and \\[]" });
|
||||
|
||||
Assert.AreEqual("This is a nasty link with escaped brackets: ] and [", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(41, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNewFormatLinkWithBackslashesInside()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh link \\ with \\ backslashes \\]" });
|
||||
|
||||
Assert.AreEqual("This is a link \\ with \\ backslashes \\", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(27, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNewFormatLinkWithEscapedAndBalancedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh [link [with \\] too many brackets \\[ ]]]" });
|
||||
|
||||
Assert.AreEqual("This is a [link [with ] too many brackets [ ]]", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(36, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLink()
|
||||
{
|
||||
@ -143,6 +226,143 @@ namespace osu.Game.Tests.Chat
|
||||
Assert.AreEqual(11, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithBalancedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [tricky [one]](https://osu.ppy.sh)!" });
|
||||
|
||||
Assert.AreEqual("This is a tricky [one]!", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(12, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithEscapedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is [another loose bracket \\]](https://osu.ppy.sh)." });
|
||||
|
||||
Assert.AreEqual("This is another loose bracket ].", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(8, result.Links[0].Index);
|
||||
Assert.AreEqual(23, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatWithBackslashes()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This link [should end with a backslash \\](https://osu.ppy.sh)." });
|
||||
Assert.AreEqual("This link should end with a backslash \\.", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(29, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithEscapedAndBalancedBrackets()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [\\]super\\[\\[ tricky [one]](https://osu.ppy.sh)!" });
|
||||
|
||||
Assert.AreEqual("This is a ]super[[ tricky [one]!", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(21, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithInlineTitle()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [this link format](https://osu.ppy.sh \"osu!\") before..." });
|
||||
|
||||
Assert.AreEqual("I haven't seen this link format before...", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(15, result.Links[0].Index);
|
||||
Assert.AreEqual(16, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithInlineTitleAndEscapedQuotes()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [this link format](https://osu.ppy.sh \"inner quote \\\" just to confuse \") before..." });
|
||||
|
||||
Assert.AreEqual("I haven't seen this link format before...", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(15, result.Links[0].Index);
|
||||
Assert.AreEqual(16, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithUrlInTextAndInlineTitle()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [https://osu.ppy.sh](https://osu.ppy.sh \"https://osu.ppy.sh\") before..." });
|
||||
|
||||
Assert.AreEqual("I haven't seen https://osu.ppy.sh before...", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(15, result.Links[0].Index);
|
||||
Assert.AreEqual(18, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithUrlAndTextInTitle()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [oh no, text here! https://osu.ppy.sh](https://osu.ppy.sh) before..." });
|
||||
|
||||
Assert.AreEqual("I haven't seen oh no, text here! https://osu.ppy.sh before...", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(15, result.Links[0].Index);
|
||||
Assert.AreEqual(36, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkWithMisleadingUrlInText()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [https://google.com](https://osu.ppy.sh) before..." });
|
||||
|
||||
Assert.AreEqual("I haven't seen https://google.com before...", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||
Assert.AreEqual(15, result.Links[0].Index);
|
||||
Assert.AreEqual(18, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkThatContractsIntoLargerLink()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "super broken https://[osu.ppy](https://reddit.com).sh/" });
|
||||
|
||||
Assert.AreEqual("super broken https://osu.ppy.sh/", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://reddit.com", result.Links[0].Url);
|
||||
Assert.AreEqual(21, result.Links[0].Index);
|
||||
Assert.AreEqual(7, result.Links[0].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkdownFormatLinkDirectlyNextToRawLink()
|
||||
{
|
||||
// the raw link has a port at the end of it, so that the raw link regex terminates at the port and doesn't consume display text from the formatted one
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "https://localhost:8080[https://osu.ppy.sh](https://osu.ppy.sh) should be two links" });
|
||||
|
||||
Assert.AreEqual("https://localhost:8080https://osu.ppy.sh should be two links", result.DisplayContent);
|
||||
Assert.AreEqual(2, result.Links.Count);
|
||||
|
||||
Assert.AreEqual("https://localhost:8080", result.Links[0].Url);
|
||||
Assert.AreEqual(0, result.Links[0].Index);
|
||||
Assert.AreEqual(22, result.Links[0].Length);
|
||||
|
||||
Assert.AreEqual("https://osu.ppy.sh", result.Links[1].Url);
|
||||
Assert.AreEqual(22, result.Links[1].Index);
|
||||
Assert.AreEqual(18, result.Links[1].Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChannelLink()
|
||||
{
|
||||
|
@ -0,0 +1,194 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Edit;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Tests.Editor
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class TestSceneHitObjectComposerDistanceSnapping : EditorClockTestScene
|
||||
{
|
||||
private TestHitObjectComposer composer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Child = composer = new TestHitObjectComposer();
|
||||
|
||||
BeatDivisor.Value = 1;
|
||||
|
||||
composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1;
|
||||
composer.EditorBeatmap.ControlPointInfo.Clear();
|
||||
|
||||
composer.EditorBeatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = 1 });
|
||||
composer.EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 });
|
||||
});
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void TestSliderMultiplier(float multiplier)
|
||||
{
|
||||
AddStep($"set multiplier = {multiplier}", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = multiplier);
|
||||
|
||||
assertSnapDistance(100 * multiplier);
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void TestSpeedMultiplier(float multiplier)
|
||||
{
|
||||
AddStep($"set multiplier = {multiplier}", () =>
|
||||
{
|
||||
composer.EditorBeatmap.ControlPointInfo.Clear();
|
||||
composer.EditorBeatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = multiplier });
|
||||
});
|
||||
|
||||
assertSnapDistance(100 * multiplier);
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void TestBeatDivisor(int divisor)
|
||||
{
|
||||
AddStep($"set divisor = {divisor}", () => BeatDivisor.Value = divisor);
|
||||
|
||||
assertSnapDistance(100f / divisor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestConvertDurationToDistance()
|
||||
{
|
||||
assertDurationToDistance(500, 50);
|
||||
assertDurationToDistance(1000, 100);
|
||||
|
||||
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
|
||||
|
||||
assertDurationToDistance(500, 100);
|
||||
assertDurationToDistance(1000, 200);
|
||||
|
||||
AddStep("set beat length = 500", () =>
|
||||
{
|
||||
composer.EditorBeatmap.ControlPointInfo.Clear();
|
||||
composer.EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 });
|
||||
});
|
||||
|
||||
assertDurationToDistance(500, 200);
|
||||
assertDurationToDistance(1000, 400);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestConvertDistanceToDuration()
|
||||
{
|
||||
assertDistanceToDuration(50, 500);
|
||||
assertDistanceToDuration(100, 1000);
|
||||
|
||||
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
|
||||
|
||||
assertDistanceToDuration(100, 500);
|
||||
assertDistanceToDuration(200, 1000);
|
||||
|
||||
AddStep("set beat length = 500", () =>
|
||||
{
|
||||
composer.EditorBeatmap.ControlPointInfo.Clear();
|
||||
composer.EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 });
|
||||
});
|
||||
|
||||
assertDistanceToDuration(200, 500);
|
||||
assertDistanceToDuration(400, 1000);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetSnappedDurationFromDistance()
|
||||
{
|
||||
assertSnappedDuration(50, 0);
|
||||
assertSnappedDuration(100, 1000);
|
||||
assertSnappedDuration(150, 1000);
|
||||
assertSnappedDuration(200, 2000);
|
||||
assertSnappedDuration(250, 2000);
|
||||
|
||||
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
|
||||
|
||||
assertSnappedDuration(50, 0);
|
||||
assertSnappedDuration(100, 0);
|
||||
assertSnappedDuration(150, 0);
|
||||
assertSnappedDuration(200, 1000);
|
||||
assertSnappedDuration(250, 1000);
|
||||
|
||||
AddStep("set beat length = 500", () =>
|
||||
{
|
||||
composer.EditorBeatmap.ControlPointInfo.Clear();
|
||||
composer.EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 });
|
||||
});
|
||||
|
||||
assertSnappedDuration(50, 0);
|
||||
assertSnappedDuration(100, 0);
|
||||
assertSnappedDuration(150, 0);
|
||||
assertSnappedDuration(200, 500);
|
||||
assertSnappedDuration(250, 500);
|
||||
assertSnappedDuration(400, 1000);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSnappedDistanceFromDistance()
|
||||
{
|
||||
assertSnappedDistance(50, 0);
|
||||
assertSnappedDistance(100, 100);
|
||||
assertSnappedDistance(150, 100);
|
||||
assertSnappedDistance(200, 200);
|
||||
assertSnappedDistance(250, 200);
|
||||
|
||||
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
|
||||
|
||||
assertSnappedDistance(50, 0);
|
||||
assertSnappedDistance(100, 0);
|
||||
assertSnappedDistance(150, 0);
|
||||
assertSnappedDistance(200, 200);
|
||||
assertSnappedDistance(250, 200);
|
||||
|
||||
AddStep("set beat length = 500", () =>
|
||||
{
|
||||
composer.EditorBeatmap.ControlPointInfo.Clear();
|
||||
composer.EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 });
|
||||
});
|
||||
|
||||
assertSnappedDistance(50, 0);
|
||||
assertSnappedDistance(100, 0);
|
||||
assertSnappedDistance(150, 0);
|
||||
assertSnappedDistance(200, 200);
|
||||
assertSnappedDistance(250, 200);
|
||||
assertSnappedDistance(400, 400);
|
||||
}
|
||||
|
||||
private void assertSnapDistance(float expectedDistance)
|
||||
=> AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(0) == expectedDistance);
|
||||
|
||||
private void assertDurationToDistance(double duration, float expectedDistance)
|
||||
=> AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(0, duration) == expectedDistance);
|
||||
|
||||
private void assertDistanceToDuration(float distance, double expectedDuration)
|
||||
=> AddAssert($"distance = {distance} -> duration = {expectedDuration}", () => composer.DistanceToDuration(0, distance) == expectedDuration);
|
||||
|
||||
private void assertSnappedDuration(float distance, double expectedDuration)
|
||||
=> AddAssert($"distance = {distance} -> duration = {expectedDuration} (snapped)", () => composer.GetSnappedDurationFromDistance(0, distance) == expectedDuration);
|
||||
|
||||
private void assertSnappedDistance(float distance, float expectedDistance)
|
||||
=> AddAssert($"distance = {distance} -> distance = {expectedDistance} (snapped)", () => composer.GetSnappedDistanceFromDistance(0, distance) == expectedDistance);
|
||||
|
||||
private class TestHitObjectComposer : OsuHitObjectComposer
|
||||
{
|
||||
public new EditorBeatmap<OsuHitObject> EditorBeatmap => base.EditorBeatmap;
|
||||
|
||||
public TestHitObjectComposer()
|
||||
: base(new OsuRuleset())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
143
osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
Normal file
143
osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Gameplay
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class TestSceneHitObjectAccentColour : OsuTestScene
|
||||
{
|
||||
private Container skinContainer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() => Child = skinContainer = new SkinProvidingContainer(new TestSkin()));
|
||||
|
||||
[Test]
|
||||
public void TestChangeComboIndexBeforeLoad()
|
||||
{
|
||||
TestDrawableHitObject hitObject = null;
|
||||
|
||||
AddStep("set combo and add hitobject", () =>
|
||||
{
|
||||
hitObject = new TestDrawableHitObject();
|
||||
hitObject.HitObject.ComboIndex = 1;
|
||||
|
||||
skinContainer.Add(hitObject);
|
||||
});
|
||||
|
||||
AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangeComboIndexDuringLoad()
|
||||
{
|
||||
TestDrawableHitObject hitObject = null;
|
||||
|
||||
AddStep("add hitobject and set combo", () =>
|
||||
{
|
||||
skinContainer.Add(hitObject = new TestDrawableHitObject());
|
||||
hitObject.HitObject.ComboIndex = 1;
|
||||
});
|
||||
|
||||
AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangeComboIndexAfterLoad()
|
||||
{
|
||||
TestDrawableHitObject hitObject = null;
|
||||
|
||||
AddStep("add hitobject", () => skinContainer.Add(hitObject = new TestDrawableHitObject()));
|
||||
AddAssert("combo colour is red", () => hitObject.AccentColour.Value == Color4.Red);
|
||||
|
||||
AddStep("change combo", () => hitObject.HitObject.ComboIndex = 1);
|
||||
AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green);
|
||||
}
|
||||
|
||||
private class TestDrawableHitObject : DrawableHitObject<TestHitObjectWithCombo>
|
||||
{
|
||||
public TestDrawableHitObject()
|
||||
: base(new TestHitObjectWithCombo())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestHitObjectWithCombo : HitObject, IHasComboInformation
|
||||
{
|
||||
public bool NewCombo { get; } = false;
|
||||
public int ComboOffset { get; } = 0;
|
||||
|
||||
public Bindable<int> IndexInCurrentComboBindable { get; } = new Bindable<int>();
|
||||
|
||||
public int IndexInCurrentCombo
|
||||
{
|
||||
get => IndexInCurrentComboBindable.Value;
|
||||
set => IndexInCurrentComboBindable.Value = value;
|
||||
}
|
||||
|
||||
public Bindable<int> ComboIndexBindable { get; } = new Bindable<int>();
|
||||
|
||||
public int ComboIndex
|
||||
{
|
||||
get => ComboIndexBindable.Value;
|
||||
set => ComboIndexBindable.Value = value;
|
||||
}
|
||||
|
||||
public Bindable<bool> LastInComboBindable { get; } = new Bindable<bool>();
|
||||
|
||||
public bool LastInCombo
|
||||
{
|
||||
get => LastInComboBindable.Value;
|
||||
set => LastInComboBindable.Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSkin : ISkin
|
||||
{
|
||||
public readonly List<Color4> ComboColours = new List<Color4>
|
||||
{
|
||||
Color4.Red,
|
||||
Color4.Green
|
||||
};
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotImplementedException();
|
||||
|
||||
public Texture GetTexture(string componentName) => throw new NotImplementedException();
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||
{
|
||||
switch (lookup)
|
||||
{
|
||||
case GlobalSkinConfiguration global:
|
||||
switch (global)
|
||||
{
|
||||
case GlobalSkinConfiguration.ComboColours:
|
||||
return SkinUtils.As<TValue>(new Bindable<List<Color4>>(ComboColours));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
Normal file
48
osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class BeatmapSetInfoEqualityTest
|
||||
{
|
||||
[Test]
|
||||
public void TestOnlineWithOnline()
|
||||
{
|
||||
var ourInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
|
||||
var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
|
||||
|
||||
Assert.AreEqual(ourInfo, otherInfo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDatabasedWithDatabased()
|
||||
{
|
||||
var ourInfo = new BeatmapSetInfo { ID = 123 };
|
||||
var otherInfo = new BeatmapSetInfo { ID = 123 };
|
||||
|
||||
Assert.AreEqual(ourInfo, otherInfo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDatabasedWithOnline()
|
||||
{
|
||||
var ourInfo = new BeatmapSetInfo { ID = 123, OnlineBeatmapSetID = 12 };
|
||||
var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 12 };
|
||||
|
||||
Assert.AreEqual(ourInfo, otherInfo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCheckNullID()
|
||||
{
|
||||
var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved };
|
||||
var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved };
|
||||
|
||||
Assert.AreNotEqual(ourInfo, otherInfo);
|
||||
}
|
||||
}
|
||||
}
|
227
osu.Game.Tests/NonVisual/ControlPointInfoTest.cs
Normal file
227
osu.Game.Tests/NonVisual/ControlPointInfoTest.cs
Normal file
@ -0,0 +1,227 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class ControlPointInfoTest
|
||||
{
|
||||
[Test]
|
||||
public void TestAdd()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new TimingControlPoint());
|
||||
cpi.Add(1000, new TimingControlPoint { BeatLength = 500 });
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddRedundantTiming()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new TimingControlPoint()); // is *not* redundant, special exception for first timing point.
|
||||
cpi.Add(1000, new TimingControlPoint()); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddRedundantDifficulty()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new DifficultyControlPoint()); // is redundant
|
||||
cpi.Add(1000, new DifficultyControlPoint()); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||
|
||||
cpi.Add(1000, new DifficultyControlPoint { SpeedMultiplier = 2 }); // is not redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddRedundantSample()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new SampleControlPoint()); // is redundant
|
||||
cpi.Add(1000, new SampleControlPoint()); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||
|
||||
cpi.Add(1000, new SampleControlPoint { SampleVolume = 50 }); // is not redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.SamplePoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddRedundantEffect()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new EffectControlPoint()); // is redundant
|
||||
cpi.Add(1000, new EffectControlPoint()); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||
|
||||
cpi.Add(1000, new EffectControlPoint { KiaiMode = true }); // is not redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddGroup()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
var group = cpi.GroupAt(1000, true);
|
||||
var group2 = cpi.GroupAt(1000, true);
|
||||
|
||||
Assert.That(group, Is.EqualTo(group2));
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGroupAtLookupOnly()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
var group = cpi.GroupAt(5000, true);
|
||||
Assert.That(group, Is.Not.Null);
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.GroupAt(1000), Is.Null);
|
||||
Assert.That(cpi.GroupAt(5000), Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddRemoveGroup()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
var group = cpi.GroupAt(1000, true);
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
|
||||
cpi.RemoveGroup(group);
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddControlPointToGroup()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
var group = cpi.GroupAt(1000, true);
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
|
||||
// usually redundant, but adding to group forces it to be added
|
||||
group.Add(new DifficultyControlPoint());
|
||||
|
||||
Assert.That(group.ControlPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddDuplicateControlPointToGroup()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
var group = cpi.GroupAt(1000, true);
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
|
||||
group.Add(new DifficultyControlPoint());
|
||||
group.Add(new DifficultyControlPoint { SpeedMultiplier = 2 });
|
||||
|
||||
Assert.That(group.ControlPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.DifficultyPoints.First().SpeedMultiplier, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRemoveControlPointFromGroup()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
var group = cpi.GroupAt(1000, true);
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
|
||||
var difficultyPoint = new DifficultyControlPoint();
|
||||
|
||||
group.Add(difficultyPoint);
|
||||
group.Remove(difficultyPoint);
|
||||
|
||||
Assert.That(group.ControlPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOrdering()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new TimingControlPoint());
|
||||
cpi.Add(1000, new TimingControlPoint { BeatLength = 500 });
|
||||
cpi.Add(10000, new TimingControlPoint { BeatLength = 200 });
|
||||
cpi.Add(5000, new TimingControlPoint { BeatLength = 100 });
|
||||
cpi.Add(3000, new DifficultyControlPoint { SpeedMultiplier = 2 });
|
||||
cpi.GroupAt(7000, true).Add(new DifficultyControlPoint { SpeedMultiplier = 4 });
|
||||
cpi.GroupAt(1000).Add(new SampleControlPoint { SampleVolume = 0 });
|
||||
cpi.GroupAt(8000, true).Add(new EffectControlPoint { KiaiMode = true });
|
||||
|
||||
Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(8));
|
||||
|
||||
Assert.That(cpi.Groups, Is.Ordered.Ascending.By(nameof(ControlPointGroup.Time)));
|
||||
|
||||
Assert.That(cpi.AllControlPoints, Is.Ordered.Ascending.By(nameof(ControlPoint.Time)));
|
||||
Assert.That(cpi.TimingPoints, Is.Ordered.Ascending.By(nameof(ControlPoint.Time)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClear()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new TimingControlPoint());
|
||||
cpi.Add(1000, new TimingControlPoint { BeatLength = 500 });
|
||||
cpi.Add(10000, new TimingControlPoint { BeatLength = 200 });
|
||||
cpi.Add(5000, new TimingControlPoint { BeatLength = 100 });
|
||||
cpi.Add(3000, new DifficultyControlPoint { SpeedMultiplier = 2 });
|
||||
cpi.GroupAt(7000, true).Add(new DifficultyControlPoint { SpeedMultiplier = 4 });
|
||||
cpi.GroupAt(1000).Add(new SampleControlPoint { SampleVolume = 0 });
|
||||
cpi.GroupAt(8000, true).Add(new EffectControlPoint { KiaiMode = true });
|
||||
|
||||
cpi.Clear();
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(0));
|
||||
}
|
||||
}
|
||||
}
|
201
osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
Normal file
201
osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
Normal file
@ -0,0 +1,201 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual.Filtering
|
||||
{
|
||||
[TestFixture]
|
||||
public class FilterMatchingTest
|
||||
{
|
||||
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
|
||||
{
|
||||
Ruleset = new RulesetInfo { ID = 5 },
|
||||
StarDifficulty = 4.0d,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
ApproachRate = 5.0f,
|
||||
DrainRate = 3.0f,
|
||||
CircleSize = 2.0f,
|
||||
},
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Artist = "The Artist",
|
||||
ArtistUnicode = "check unicode too",
|
||||
Title = "Title goes here",
|
||||
TitleUnicode = "Title goes here",
|
||||
AuthorString = "The Author",
|
||||
Source = "unit tests",
|
||||
Tags = "look for tags too",
|
||||
},
|
||||
Version = "version as well",
|
||||
Length = 2500,
|
||||
BPM = 160,
|
||||
BeatDivisor = 12,
|
||||
Status = BeatmapSetOnlineStatus.Loved
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestCriteriaMatchingNoRuleset()
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria();
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.IsFalse(carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCriteriaMatchingSpecificRuleset()
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { ID = 6 }
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.IsTrue(carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCriteriaMatchingConvertedBeatmaps()
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { ID = 6 },
|
||||
AllowConvertedBeatmaps = true
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.IsFalse(carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestCriteriaMatchingRangeMin(bool inclusive)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { ID = 6 },
|
||||
AllowConvertedBeatmaps = true,
|
||||
ApproachRate = new FilterCriteria.OptionalRange<float>
|
||||
{
|
||||
IsLowerInclusive = inclusive,
|
||||
Min = 5.0f
|
||||
}
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.AreEqual(!inclusive, carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestCriteriaMatchingRangeMax(bool inclusive)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { ID = 6 },
|
||||
AllowConvertedBeatmaps = true,
|
||||
BPM = new FilterCriteria.OptionalRange<double>
|
||||
{
|
||||
IsUpperInclusive = inclusive,
|
||||
Max = 160d
|
||||
}
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.AreEqual(!inclusive, carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("artist", false)]
|
||||
[TestCase("artist title author", false)]
|
||||
[TestCase("an artist", true)]
|
||||
[TestCase("tags too", false)]
|
||||
[TestCase("version", false)]
|
||||
[TestCase("an auteur", true)]
|
||||
public void TestCriteriaMatchingTerms(string terms, bool filtered)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { ID = 6 },
|
||||
AllowConvertedBeatmaps = true,
|
||||
SearchText = terms
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.AreEqual(filtered, carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", false)]
|
||||
[TestCase("The", false)]
|
||||
[TestCase("THE", false)]
|
||||
[TestCase("author", false)]
|
||||
[TestCase("the author", false)]
|
||||
[TestCase("the author AND then something else", true)]
|
||||
[TestCase("unknown", true)]
|
||||
public void TestCriteriaMatchingCreator(string creatorName, bool filtered)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Creator = new FilterCriteria.OptionalTextFilter { SearchTerm = creatorName }
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.AreEqual(filtered, carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", false)]
|
||||
[TestCase("The", false)]
|
||||
[TestCase("THE", false)]
|
||||
[TestCase("artist", false)]
|
||||
[TestCase("the artist", false)]
|
||||
[TestCase("the artist AND then something else", true)]
|
||||
[TestCase("unicode too", false)]
|
||||
[TestCase("unknown", true)]
|
||||
public void TestCriteriaMatchingArtist(string artistName, bool filtered)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Artist = new FilterCriteria.OptionalTextFilter { SearchTerm = artistName }
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.AreEqual(filtered, carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", false)]
|
||||
[TestCase("artist", false)]
|
||||
[TestCase("unknown", true)]
|
||||
public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
exampleBeatmapInfo.Metadata.ArtistUnicode = null;
|
||||
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Artist = new FilterCriteria.OptionalTextFilter { SearchTerm = artistName }
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.AreEqual(filtered, carouselItem.Filtered.Value);
|
||||
}
|
||||
}
|
||||
}
|
184
osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs
Normal file
184
osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs
Normal file
@ -0,0 +1,184 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual.Filtering
|
||||
{
|
||||
[TestFixture]
|
||||
public class FilterQueryParserTest
|
||||
{
|
||||
[Test]
|
||||
public void TestApplyQueriesBareWords()
|
||||
{
|
||||
const string query = "looking for a beatmap";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("looking for a beatmap", filterCriteria.SearchText);
|
||||
Assert.AreEqual(4, filterCriteria.SearchTerms.Length);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following tests have been written a bit strangely (they don't check exact
|
||||
* bound equality with what the filter says).
|
||||
* This is to account for floating-point arithmetic issues.
|
||||
* For example, specifying a bpm<140 filter would previously match beatmaps with BPM
|
||||
* of 139.99999, which would be displayed in the UI as 140.
|
||||
* Due to this the tests check the last tick inside the range and the first tick
|
||||
* outside of the range.
|
||||
*/
|
||||
|
||||
[Test]
|
||||
public void TestApplyStarQueries()
|
||||
{
|
||||
const string query = "stars<4 easy";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("easy", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(1, filterCriteria.SearchTerms.Length);
|
||||
Assert.IsNotNull(filterCriteria.StarDifficulty.Max);
|
||||
Assert.Greater(filterCriteria.StarDifficulty.Max, 3.99d);
|
||||
Assert.Less(filterCriteria.StarDifficulty.Max, 4.00d);
|
||||
Assert.IsNull(filterCriteria.StarDifficulty.Min);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyApproachRateQueries()
|
||||
{
|
||||
const string query = "ar>=9 difficult";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("difficult", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(1, filterCriteria.SearchTerms.Length);
|
||||
Assert.IsNotNull(filterCriteria.ApproachRate.Min);
|
||||
Assert.Greater(filterCriteria.ApproachRate.Min, 8.9f);
|
||||
Assert.Less(filterCriteria.ApproachRate.Min, 9.0f);
|
||||
Assert.IsNull(filterCriteria.ApproachRate.Max);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyDrainRateQueries()
|
||||
{
|
||||
const string query = "dr>2 quite specific dr<:6";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("quite specific", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(2, filterCriteria.SearchTerms.Length);
|
||||
Assert.Greater(filterCriteria.DrainRate.Min, 2.0f);
|
||||
Assert.Less(filterCriteria.DrainRate.Min, 2.1f);
|
||||
Assert.Greater(filterCriteria.DrainRate.Max, 6.0f);
|
||||
Assert.Less(filterCriteria.DrainRate.Min, 6.1f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyBPMQueries()
|
||||
{
|
||||
const string query = "bpm>:200 gotta go fast";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("gotta go fast", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(3, filterCriteria.SearchTerms.Length);
|
||||
Assert.IsNotNull(filterCriteria.BPM.Min);
|
||||
Assert.Greater(filterCriteria.BPM.Min, 199.99d);
|
||||
Assert.Less(filterCriteria.BPM.Min, 200.00d);
|
||||
Assert.IsNull(filterCriteria.BPM.Max);
|
||||
}
|
||||
|
||||
private static object[] lengthQueryExamples =
|
||||
{
|
||||
new object[] { "6ms", TimeSpan.FromMilliseconds(6), TimeSpan.FromMilliseconds(1) },
|
||||
new object[] { "23s", TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(1) },
|
||||
new object[] { "9m", TimeSpan.FromMinutes(9), TimeSpan.FromMinutes(1) },
|
||||
new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1) },
|
||||
new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1) },
|
||||
};
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(nameof(lengthQueryExamples))]
|
||||
public void TestApplyLengthQueries(string lengthQuery, TimeSpan expectedLength, TimeSpan scale)
|
||||
{
|
||||
string query = $"length={lengthQuery} time";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("time", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(1, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min);
|
||||
Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyDivisorQueries()
|
||||
{
|
||||
const string query = "that's a time signature alright! divisor:12";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("that's a time signature alright!", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(5, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual(12, filterCriteria.BeatDivisor.Min);
|
||||
Assert.IsTrue(filterCriteria.BeatDivisor.IsLowerInclusive);
|
||||
Assert.AreEqual(12, filterCriteria.BeatDivisor.Max);
|
||||
Assert.IsTrue(filterCriteria.BeatDivisor.IsUpperInclusive);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyStatusQueries()
|
||||
{
|
||||
const string query = "I want the pp status=ranked";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("I want the pp", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(4, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual(BeatmapSetOnlineStatus.Ranked, filterCriteria.OnlineStatus.Min);
|
||||
Assert.IsTrue(filterCriteria.OnlineStatus.IsLowerInclusive);
|
||||
Assert.AreEqual(BeatmapSetOnlineStatus.Ranked, filterCriteria.OnlineStatus.Max);
|
||||
Assert.IsTrue(filterCriteria.OnlineStatus.IsUpperInclusive);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyCreatorQueries()
|
||||
{
|
||||
const string query = "beatmap specifically by creator=my_fav";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("beatmap specifically by", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(3, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual("my_fav", filterCriteria.Creator.SearchTerm);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyArtistQueries()
|
||||
{
|
||||
const string query = "find me songs by artist=singer please";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("find me songs by please", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(5, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual("singer", filterCriteria.Artist.SearchTerm);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyArtistQueriesWithSpaces()
|
||||
{
|
||||
const string query = "really like artist=\"name with space\" yes";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("really like yes", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(3, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual("name with space", filterCriteria.Artist.SearchTerm);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyArtistQueriesOneDoubleQuote()
|
||||
{
|
||||
const string query = "weird artist=double\"quote";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("weird", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(1, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual("double\"quote", filterCriteria.Artist.SearchTerm);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Replays;
|
||||
@ -9,7 +10,7 @@ using osu.Game.Rulesets.Replays;
|
||||
namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class FramedReplayinputHandlerTest
|
||||
public class FramedReplayInputHandlerTest
|
||||
{
|
||||
private Replay replay;
|
||||
private TestInputHandler handler;
|
||||
@ -160,10 +161,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
[Test]
|
||||
public void TestRewindInsideImportantSection()
|
||||
{
|
||||
// fast forward to important section
|
||||
while (handler.SetFrameFromTime(3000) != null)
|
||||
{
|
||||
}
|
||||
fastForwardToPoint(3000);
|
||||
|
||||
setTime(4000, 4000);
|
||||
confirmCurrentFrame(4);
|
||||
@ -205,10 +203,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
[Test]
|
||||
public void TestRewindOutOfImportantSection()
|
||||
{
|
||||
// fast forward to important section
|
||||
while (handler.SetFrameFromTime(3500) != null)
|
||||
{
|
||||
}
|
||||
fastForwardToPoint(3500);
|
||||
|
||||
confirmCurrentFrame(3);
|
||||
confirmNextFrame(4);
|
||||
@ -227,6 +222,17 @@ namespace osu.Game.Tests.NonVisual
|
||||
confirmNextFrame(2);
|
||||
}
|
||||
|
||||
private void fastForwardToPoint(double destination)
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
if (handler.SetFrameFromTime(destination) == null)
|
||||
return;
|
||||
}
|
||||
|
||||
throw new TimeoutException("Seek was never fulfilled");
|
||||
}
|
||||
|
||||
private void setTime(double set, double? expect)
|
||||
{
|
||||
Assert.AreEqual(expect, handler.SetFrameFromTime(set));
|
||||
@ -274,6 +280,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
public TestInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
FrameAccuratePlayback = true;
|
||||
}
|
||||
|
||||
protected override double AllowedImportantTimeSpan => 1000;
|
@ -11,13 +11,13 @@ namespace osu.Game.Tests.Resources
|
||||
{
|
||||
public static Stream OpenResource(string name) => new DllResourceStore("osu.Game.Tests.dll").GetStream($"Resources/{name}");
|
||||
|
||||
public static Stream GetTestBeatmapStream() => new DllResourceStore("osu.Game.Resources.dll").GetStream("Beatmaps/241526 Soleily - Renatus.osz");
|
||||
public static Stream GetTestBeatmapStream(bool virtualTrack = false) => new DllResourceStore("osu.Game.Resources.dll").GetStream($"Beatmaps/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz");
|
||||
|
||||
public static string GetTestBeatmapForImport()
|
||||
public static string GetTestBeatmapForImport(bool virtualTrack = false)
|
||||
{
|
||||
var temp = Path.GetTempFileName() + ".osz";
|
||||
|
||||
using (var stream = GetTestBeatmapStream())
|
||||
using (var stream = GetTestBeatmapStream(virtualTrack))
|
||||
using (var newFile = File.Create(temp))
|
||||
stream.CopyTo(newFile);
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
osu file format v7
|
||||
|
||||
[TimingPoints]
|
||||
0,100,4,2,0,100,1,0
|
||||
12,500,4,2,0,100,1,0
|
||||
1000,-10,4,2,0,100,0,0
|
||||
2000,-54,4,2,0,100,0,0
|
||||
3000,-200,4,2,0,100,0,0
|
5
osu.Game.Tests/Resources/corrupted-header.osu
Normal file
5
osu.Game.Tests/Resources/corrupted-header.osu
Normal file
@ -0,0 +1,5 @@
|
||||
ow computerosu file format v14
|
||||
|
||||
[Metadata]
|
||||
Title: Beatmap with corrupted header
|
||||
Creator: Evil Hacker
|
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
[Metadata]
|
||||
Title: The dog ate the file header
|
||||
Creator: Why does this keep happening
|
8
osu.Game.Tests/Resources/empty-lines-at-start.osu
Normal file
8
osu.Game.Tests/Resources/empty-lines-at-start.osu
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
|
||||
osu file format v14
|
||||
|
||||
[Metadata]
|
||||
Title: Empty lines at start
|
||||
Creator: Edge Case Hunter
|
14
osu.Game.Tests/Resources/invalid-events.osu
Normal file
14
osu.Game.Tests/Resources/invalid-events.osu
Normal file
@ -0,0 +1,14 @@
|
||||
osu file format v14
|
||||
|
||||
[Events]
|
||||
bad,event,this,should,fail
|
||||
//Background and Video events
|
||||
0,0,"machinetop_background.jpg",0,0
|
||||
//Break Periods
|
||||
2,122474,140135
|
||||
//Storyboard Layer 0 (Background)
|
||||
this,is,also,bad
|
||||
//Storyboard Layer 1 (Fail)
|
||||
//Storyboard Layer 2 (Pass)
|
||||
//Storyboard Layer 3 (Foreground)
|
||||
//Storyboard Sound Samples
|
4
osu.Game.Tests/Resources/missing-header.osu
Normal file
4
osu.Game.Tests/Resources/missing-header.osu
Normal file
@ -0,0 +1,4 @@
|
||||
[Metadata]
|
||||
|
||||
Title: Beatmap with no header
|
||||
Creator: Incredibly Evil Hacker
|
4
osu.Game.Tests/Resources/no-empty-line-after-header.osu
Normal file
4
osu.Game.Tests/Resources/no-empty-line-after-header.osu
Normal file
@ -0,0 +1,4 @@
|
||||
osu file format v14
|
||||
[Metadata]
|
||||
Title: No empty line delimiting header from contents
|
||||
Creator: Edge Case Hunter
|
@ -1,5 +1,6 @@
|
||||
[General]
|
||||
Name: test skin
|
||||
TestLookup: TestValue
|
||||
|
||||
[Colours]
|
||||
Combo1 : 142,199,255
|
||||
|
@ -0,0 +1,5 @@
|
||||
osu file format v14
|
||||
|
||||
[TimingPoints]
|
||||
0,-200,4,1,0,100,0,0
|
||||
2000,100,1,1,0,100,1,0
|
@ -23,13 +23,13 @@ namespace osu.Game.Tests.Scores.IO
|
||||
public class ImportScoreTest
|
||||
{
|
||||
[Test]
|
||||
public void TestBasicImport()
|
||||
public async Task TestBasicImport()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestBasicImport"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var osu = await loadOsu(host);
|
||||
|
||||
var toImport = new ScoreInfo
|
||||
{
|
||||
@ -43,7 +43,7 @@ namespace osu.Game.Tests.Scores.IO
|
||||
OnlineScoreID = 12345,
|
||||
};
|
||||
|
||||
var imported = loadIntoOsu(osu, toImport);
|
||||
var imported = await loadIntoOsu(osu, toImport);
|
||||
|
||||
Assert.AreEqual(toImport.Rank, imported.Rank);
|
||||
Assert.AreEqual(toImport.TotalScore, imported.TotalScore);
|
||||
@ -62,20 +62,20 @@ namespace osu.Game.Tests.Scores.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportMods()
|
||||
public async Task TestImportMods()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportMods"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var osu = await loadOsu(host);
|
||||
|
||||
var toImport = new ScoreInfo
|
||||
{
|
||||
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
||||
};
|
||||
|
||||
var imported = loadIntoOsu(osu, toImport);
|
||||
var imported = await loadIntoOsu(osu, toImport);
|
||||
|
||||
Assert.IsTrue(imported.Mods.Any(m => m is OsuModHardRock));
|
||||
Assert.IsTrue(imported.Mods.Any(m => m is OsuModDoubleTime));
|
||||
@ -88,13 +88,13 @@ namespace osu.Game.Tests.Scores.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportStatistics()
|
||||
public async Task TestImportStatistics()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportStatistics"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var osu = await loadOsu(host);
|
||||
|
||||
var toImport = new ScoreInfo
|
||||
{
|
||||
@ -105,7 +105,7 @@ namespace osu.Game.Tests.Scores.IO
|
||||
}
|
||||
};
|
||||
|
||||
var imported = loadIntoOsu(osu, toImport);
|
||||
var imported = await loadIntoOsu(osu, toImport);
|
||||
|
||||
Assert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]);
|
||||
Assert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]);
|
||||
@ -117,28 +117,72 @@ namespace osu.Game.Tests.Scores.IO
|
||||
}
|
||||
}
|
||||
|
||||
private ScoreInfo loadIntoOsu(OsuGameBase osu, ScoreInfo score)
|
||||
[Test]
|
||||
public async Task TestImportWithDeletedBeatmapSet()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWithDeletedBeatmapSet"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = await loadOsu(host);
|
||||
|
||||
var toImport = new ScoreInfo
|
||||
{
|
||||
Hash = Guid.NewGuid().ToString(),
|
||||
Statistics = new Dictionary<HitResult, int>
|
||||
{
|
||||
{ HitResult.Perfect, 100 },
|
||||
{ HitResult.Miss, 50 }
|
||||
}
|
||||
};
|
||||
|
||||
var imported = await loadIntoOsu(osu, toImport);
|
||||
|
||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||
|
||||
beatmapManager.Delete(beatmapManager.QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == imported.Beatmap.ID)));
|
||||
Assert.That(scoreManager.Query(s => s.ID == imported.ID).DeletePending, Is.EqualTo(true));
|
||||
|
||||
var secondImport = await loadIntoOsu(osu, imported);
|
||||
Assert.That(secondImport, Is.Null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ScoreInfo> loadIntoOsu(OsuGameBase osu, ScoreInfo score)
|
||||
{
|
||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
score.Beatmap = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
|
||||
score.Ruleset = new OsuRuleset().RulesetInfo;
|
||||
if (score.Beatmap == null)
|
||||
score.Beatmap = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
|
||||
|
||||
if (score.Ruleset == null)
|
||||
score.Ruleset = new OsuRuleset().RulesetInfo;
|
||||
|
||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||
scoreManager.Import(score);
|
||||
await scoreManager.Import(score);
|
||||
|
||||
return scoreManager.GetAllUsableScores().First();
|
||||
return scoreManager.GetAllUsableScores().FirstOrDefault();
|
||||
}
|
||||
|
||||
private OsuGameBase loadOsu(GameHost host)
|
||||
private async Task<OsuGameBase> loadOsu(GameHost host)
|
||||
{
|
||||
var osu = new OsuGameBase();
|
||||
|
||||
#pragma warning disable 4014
|
||||
Task.Run(() => host.Run(osu));
|
||||
#pragma warning restore 4014
|
||||
|
||||
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
||||
|
||||
var beatmapFile = TestResources.GetTestBeatmapForImport();
|
||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
||||
beatmapManager.Import(beatmapFile);
|
||||
await beatmapManager.Import(beatmapFile);
|
||||
|
||||
return osu;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK.Graphics;
|
||||
@ -20,12 +20,14 @@ namespace osu.Game.Tests.Skins
|
||||
var decoder = new LegacySkinDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource(hasColours ? "skin.ini" : "skin-empty.ini"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var comboColors = decoder.Decode(stream).ComboColours;
|
||||
|
||||
List<Color4> expectedColors;
|
||||
|
||||
if (hasColours)
|
||||
{
|
||||
expectedColors = new List<Color4>
|
||||
{
|
||||
new Color4(142, 199, 255, 255),
|
||||
@ -33,6 +35,7 @@ namespace osu.Game.Tests.Skins
|
||||
new Color4(128, 255, 255, 255),
|
||||
new Color4(100, 100, 100, 100),
|
||||
};
|
||||
}
|
||||
else
|
||||
expectedColors = new DefaultSkin().Configuration.ComboColours;
|
||||
|
||||
@ -41,5 +44,20 @@ namespace osu.Game.Tests.Skins
|
||||
Assert.AreEqual(expectedColors[i], comboColors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeGeneral()
|
||||
{
|
||||
var decoder = new LegacySkinDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("skin.ini"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var config = decoder.Decode(stream);
|
||||
|
||||
Assert.AreEqual("test skin", config.SkinInfo.Name);
|
||||
Assert.AreEqual("TestValue", config.ConfigDictionary["TestLookup"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
158
osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
Normal file
158
osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
Normal file
@ -0,0 +1,158 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Skins
|
||||
{
|
||||
[TestFixture]
|
||||
[HeadlessTest]
|
||||
public class TestSceneSkinConfigurationLookup : OsuTestScene
|
||||
{
|
||||
private LegacySkin source1;
|
||||
private LegacySkin source2;
|
||||
private SkinRequester requester;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
Add(new SkinProvidingContainer(source1 = new SkinSource())
|
||||
.WithChild(new SkinProvidingContainer(source2 = new SkinSource())
|
||||
.WithChild(requester = new SkinRequester())));
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestBasicLookup()
|
||||
{
|
||||
AddStep("Add config values", () =>
|
||||
{
|
||||
source1.Configuration.ConfigDictionary["Lookup"] = "source1";
|
||||
source2.Configuration.ConfigDictionary["Lookup"] = "source2";
|
||||
});
|
||||
|
||||
AddAssert("Check lookup finds source2", () => requester.GetConfig<string, string>("Lookup")?.Value == "source2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFloatLookup()
|
||||
{
|
||||
AddStep("Add config values", () => source1.Configuration.ConfigDictionary["FloatTest"] = "1.1");
|
||||
AddAssert("Check float parse lookup", () => requester.GetConfig<string, float>("FloatTest")?.Value == 1.1f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBoolLookup()
|
||||
{
|
||||
AddStep("Add config values", () => source1.Configuration.ConfigDictionary["BoolTest"] = "1");
|
||||
AddAssert("Check bool parse lookup", () => requester.GetConfig<string, bool>("BoolTest")?.Value == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEnumLookup()
|
||||
{
|
||||
AddStep("Add config values", () => source1.Configuration.ConfigDictionary["Test"] = "Test2");
|
||||
AddAssert("Check enum parse lookup", () => requester.GetConfig<LookupType, ValueType>(LookupType.Test)?.Value == ValueType.Test2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLookupFailure()
|
||||
{
|
||||
AddAssert("Check lookup failure", () => requester.GetConfig<string, float>("Lookup") == null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLookupNull()
|
||||
{
|
||||
AddStep("Add config values", () => source1.Configuration.ConfigDictionary["Lookup"] = null);
|
||||
|
||||
AddAssert("Check lookup null", () =>
|
||||
{
|
||||
var bindable = requester.GetConfig<string, string>("Lookup");
|
||||
return bindable != null && bindable.Value == null;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestColourLookup()
|
||||
{
|
||||
AddStep("Add config colour", () => source1.Configuration.CustomColours["Lookup"] = Color4.Red);
|
||||
AddAssert("Check colour lookup", () => requester.GetConfig<SkinCustomColourLookup, Color4>(new SkinCustomColourLookup("Lookup"))?.Value == Color4.Red);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGlobalLookup()
|
||||
{
|
||||
AddAssert("Check combo colours", () => requester.GetConfig<GlobalSkinConfiguration, List<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value?.Count > 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWrongColourType()
|
||||
{
|
||||
AddStep("Add config colour", () => source1.Configuration.CustomColours["Lookup"] = Color4.Red);
|
||||
|
||||
AddAssert("perform incorrect lookup", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
requester.GetConfig<SkinCustomColourLookup, int>(new SkinCustomColourLookup("Lookup"));
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public enum LookupType
|
||||
{
|
||||
Test
|
||||
}
|
||||
|
||||
public enum ValueType
|
||||
{
|
||||
Test1,
|
||||
Test2,
|
||||
Test3
|
||||
}
|
||||
|
||||
public class SkinSource : LegacySkin
|
||||
{
|
||||
public SkinSource()
|
||||
: base(new SkinInfo(), null, null, string.Empty)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class SkinRequester : Drawable, ISkin
|
||||
{
|
||||
private ISkinSource skin;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component);
|
||||
|
||||
public Texture GetTexture(string componentName) => skin.GetTexture(componentName);
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,15 +7,16 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -35,7 +36,7 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneBackgroundScreenBeatmap : ManualInputManagerTestScene
|
||||
public class TestSceneUserDimContainer : ManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@ -49,29 +50,17 @@ namespace osu.Game.Tests.Visual.Background
|
||||
private DummySongSelect songSelect;
|
||||
private TestPlayerLoader playerLoader;
|
||||
private TestPlayer player;
|
||||
private DatabaseContextFactory factory;
|
||||
private BeatmapManager manager;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
private void load(GameHost host, AudioManager audio)
|
||||
{
|
||||
factory = new DatabaseContextFactory(LocalStorage);
|
||||
factory.ResetDatabase();
|
||||
|
||||
using (var usage = factory.Get())
|
||||
usage.Migrate();
|
||||
|
||||
factory.ResetDatabase();
|
||||
|
||||
using (var usage = factory.Get())
|
||||
usage.Migrate();
|
||||
|
||||
Dependencies.Cache(rulesets = new RulesetStore(factory));
|
||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, host, Beatmap.Default));
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
|
||||
Dependencies.Cache(new OsuConfigManager(LocalStorage));
|
||||
|
||||
manager.Import(TestResources.GetTestBeatmapForImport());
|
||||
manager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
||||
|
||||
Beatmap.SetDefault();
|
||||
}
|
||||
@ -130,20 +119,20 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
performFullSetup();
|
||||
createFakeStoryboard();
|
||||
AddStep("Storyboard Enabled", () =>
|
||||
AddStep("Enable Storyboard", () =>
|
||||
{
|
||||
player.ReplacesBackground.Value = true;
|
||||
player.StoryboardEnabled.Value = true;
|
||||
});
|
||||
waitForDim();
|
||||
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible());
|
||||
AddStep("Storyboard Disabled", () =>
|
||||
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
|
||||
AddStep("Disable Storyboard", () =>
|
||||
{
|
||||
player.ReplacesBackground.Value = false;
|
||||
player.StoryboardEnabled.Value = false;
|
||||
});
|
||||
waitForDim();
|
||||
AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && player.IsStoryboardInvisible());
|
||||
AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -160,22 +149,44 @@ namespace osu.Game.Tests.Visual.Background
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the <see cref="UserDimContainer"/> is properly accepting user-defined visual changes at all.
|
||||
/// Ensure <see cref="UserDimContainer"/> is properly accepting user-defined visual changes for a background.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void DisableUserDimTest()
|
||||
public void DisableUserDimBackgroundTest()
|
||||
{
|
||||
performFullSetup();
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("EnableUserDim disabled", () => songSelect.DimEnabled.Value = false);
|
||||
AddStep("Enable user dim", () => songSelect.DimEnabled.Value = false);
|
||||
waitForDim();
|
||||
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsUserBlurDisabled());
|
||||
AddStep("EnableUserDim enabled", () => songSelect.DimEnabled.Value = true);
|
||||
AddStep("Disable user dim", () => songSelect.DimEnabled.Value = true);
|
||||
waitForDim();
|
||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure <see cref="UserDimContainer"/> is properly accepting user-defined visual changes for a storyboard.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void DisableUserDimStoryboardTest()
|
||||
{
|
||||
performFullSetup();
|
||||
createFakeStoryboard();
|
||||
AddStep("Enable Storyboard", () =>
|
||||
{
|
||||
player.ReplacesBackground.Value = true;
|
||||
player.StoryboardEnabled.Value = true;
|
||||
});
|
||||
AddStep("Enable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = true);
|
||||
AddStep("Set dim level to 1", () => songSelect.DimLevel.Value = 1f);
|
||||
waitForDim();
|
||||
AddAssert("Storyboard is invisible", () => !player.IsStoryboardVisible);
|
||||
AddStep("Disable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = false);
|
||||
waitForDim();
|
||||
AddAssert("Storyboard is visible", () => player.IsStoryboardVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the visual settings container retains dim and blur when pausing
|
||||
/// </summary>
|
||||
@ -240,14 +251,15 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
player.StoryboardEnabled.Value = false;
|
||||
player.ReplacesBackground.Value = false;
|
||||
player.CurrentStoryboardContainer.Add(new OsuSpriteText
|
||||
player.DimmableStoryboard.Add(new OsuSpriteText
|
||||
{
|
||||
Size = new Vector2(250, 50),
|
||||
Size = new Vector2(500, 50),
|
||||
Alpha = 1,
|
||||
Colour = Color4.Tomato,
|
||||
Colour = Color4.White,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = "THIS IS A STORYBOARD",
|
||||
Font = new FontUsage(size: 50)
|
||||
});
|
||||
});
|
||||
|
||||
@ -273,6 +285,12 @@ namespace osu.Game.Tests.Visual.Background
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
rulesets?.Dispose();
|
||||
}
|
||||
|
||||
private class DummySongSelect : PlaySongSelect
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground()
|
||||
@ -299,7 +317,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
|
||||
|
||||
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * 25);
|
||||
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
|
||||
|
||||
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
|
||||
|
||||
@ -332,17 +350,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
|
||||
protected override UserDimContainer CreateStoryboardContainer()
|
||||
{
|
||||
return new TestUserDimContainer(true)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 1,
|
||||
EnableUserDim = { Value = true }
|
||||
};
|
||||
}
|
||||
|
||||
public UserDimContainer CurrentStoryboardContainer => StoryboardContainer;
|
||||
public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
|
||||
|
||||
// Whether or not the player should be allowed to load.
|
||||
public bool BlockLoad;
|
||||
@ -356,9 +364,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsStoryboardVisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha == 1;
|
||||
|
||||
public bool IsStoryboardInvisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha <= 1;
|
||||
public bool IsStoryboardVisible => DimmableStoryboard.ContentDisplayed;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config, CancellationToken token)
|
||||
@ -391,15 +397,15 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private class FadeAccessibleBackground : BackgroundScreenBeatmap
|
||||
{
|
||||
protected override UserDimContainer CreateFadeContainer() => fadeContainer = new TestUserDimContainer { RelativeSizeAxes = Axes.Both };
|
||||
protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
public Color4 CurrentColour => fadeContainer.CurrentColour;
|
||||
public Color4 CurrentColour => dimmable.CurrentColour;
|
||||
|
||||
public float CurrentAlpha => fadeContainer.CurrentAlpha;
|
||||
public float CurrentAlpha => dimmable.CurrentAlpha;
|
||||
|
||||
public Vector2 CurrentBlur => Background.BlurSigma;
|
||||
|
||||
private TestUserDimContainer fadeContainer;
|
||||
private TestDimmableBackground dimmable;
|
||||
|
||||
public FadeAccessibleBackground(WorkingBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
@ -407,15 +413,10 @@ namespace osu.Game.Tests.Visual.Background
|
||||
}
|
||||
}
|
||||
|
||||
private class TestUserDimContainer : UserDimContainer
|
||||
private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground
|
||||
{
|
||||
public Color4 CurrentColour => DimContainer.Colour;
|
||||
public float CurrentAlpha => DimContainer.Alpha;
|
||||
|
||||
public TestUserDimContainer(bool isStoryboard = false)
|
||||
: base(isStoryboard)
|
||||
{
|
||||
}
|
||||
public Color4 CurrentColour => Content.Colour;
|
||||
public float CurrentAlpha => Content.Alpha;
|
||||
}
|
||||
}
|
||||
}
|
@ -14,94 +14,132 @@ namespace osu.Game.Tests.Visual.Components
|
||||
[TestFixture]
|
||||
public class TestSceneIdleTracker : ManualInputManagerTestScene
|
||||
{
|
||||
private readonly IdleTrackingBox box1;
|
||||
private readonly IdleTrackingBox box2;
|
||||
private readonly IdleTrackingBox box3;
|
||||
private readonly IdleTrackingBox box4;
|
||||
private IdleTrackingBox box1;
|
||||
private IdleTrackingBox box2;
|
||||
private IdleTrackingBox box3;
|
||||
private IdleTrackingBox box4;
|
||||
|
||||
public TestSceneIdleTracker()
|
||||
private IdleTrackingBox[] boxes;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
Children = new Drawable[]
|
||||
InputManager.MoveMouseTo(Vector2.Zero);
|
||||
|
||||
Children = boxes = new[]
|
||||
{
|
||||
box1 = new IdleTrackingBox(1000)
|
||||
box1 = new IdleTrackingBox(2000)
|
||||
{
|
||||
Name = "TopLeft",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Red,
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
},
|
||||
box2 = new IdleTrackingBox(2000)
|
||||
box2 = new IdleTrackingBox(4000)
|
||||
{
|
||||
Name = "TopRight",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Green,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
},
|
||||
box3 = new IdleTrackingBox(3000)
|
||||
box3 = new IdleTrackingBox(6000)
|
||||
{
|
||||
Name = "BottomLeft",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Blue,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
},
|
||||
box4 = new IdleTrackingBox(4000)
|
||||
box4 = new IdleTrackingBox(8000)
|
||||
{
|
||||
Name = "BottomRight",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Orange,
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestNudge()
|
||||
{
|
||||
AddStep("move mouse to top left", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("move to top left", () => InputManager.MoveMouseTo(box1));
|
||||
|
||||
AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
|
||||
waitForAllIdle();
|
||||
|
||||
AddStep("nudge mouse", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre + new Vector2(1)));
|
||||
|
||||
AddAssert("check not idle", () => !box1.IsIdle);
|
||||
AddAssert("check idle", () => box2.IsIdle);
|
||||
AddAssert("check idle", () => box3.IsIdle);
|
||||
AddAssert("check idle", () => box4.IsIdle);
|
||||
checkIdleStatus(1, false);
|
||||
checkIdleStatus(2, true);
|
||||
checkIdleStatus(3, true);
|
||||
checkIdleStatus(4, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMovement()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(box2.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("move to top right", () => InputManager.MoveMouseTo(box2));
|
||||
|
||||
AddAssert("check not idle", () => box1.IsIdle);
|
||||
AddAssert("check not idle", () => !box2.IsIdle);
|
||||
AddAssert("check idle", () => box3.IsIdle);
|
||||
AddAssert("check idle", () => box4.IsIdle);
|
||||
checkIdleStatus(1, true);
|
||||
checkIdleStatus(2, false);
|
||||
checkIdleStatus(3, true);
|
||||
checkIdleStatus(4, true);
|
||||
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(box3.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(box4.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("move to bottom left", () => InputManager.MoveMouseTo(box3));
|
||||
AddStep("move to bottom right", () => InputManager.MoveMouseTo(box4));
|
||||
|
||||
AddAssert("check not idle", () => box1.IsIdle);
|
||||
AddAssert("check not idle", () => !box2.IsIdle);
|
||||
AddAssert("check idle", () => !box3.IsIdle);
|
||||
AddAssert("check idle", () => !box4.IsIdle);
|
||||
checkIdleStatus(1, true);
|
||||
checkIdleStatus(2, false);
|
||||
checkIdleStatus(3, false);
|
||||
checkIdleStatus(4, false);
|
||||
|
||||
AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
|
||||
waitForAllIdle();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTimings()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("move to centre", () => InputManager.MoveMouseTo(Content));
|
||||
|
||||
checkIdleStatus(1, false);
|
||||
checkIdleStatus(2, false);
|
||||
checkIdleStatus(3, false);
|
||||
checkIdleStatus(4, false);
|
||||
|
||||
AddAssert("check not idle", () => !box1.IsIdle && !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
|
||||
AddUntilStep("Wait for idle", () => box1.IsIdle);
|
||||
AddAssert("check not idle", () => !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
|
||||
|
||||
checkIdleStatus(1, true);
|
||||
checkIdleStatus(2, false);
|
||||
checkIdleStatus(3, false);
|
||||
checkIdleStatus(4, false);
|
||||
|
||||
AddUntilStep("Wait for idle", () => box2.IsIdle);
|
||||
AddAssert("check not idle", () => !box3.IsIdle && !box4.IsIdle);
|
||||
|
||||
checkIdleStatus(1, true);
|
||||
checkIdleStatus(2, true);
|
||||
checkIdleStatus(3, false);
|
||||
checkIdleStatus(4, false);
|
||||
|
||||
AddUntilStep("Wait for idle", () => box3.IsIdle);
|
||||
|
||||
checkIdleStatus(1, true);
|
||||
checkIdleStatus(2, true);
|
||||
checkIdleStatus(3, true);
|
||||
checkIdleStatus(4, false);
|
||||
|
||||
waitForAllIdle();
|
||||
}
|
||||
|
||||
private void checkIdleStatus(int box, bool expectedIdle)
|
||||
{
|
||||
AddAssert($"box {box} is {(expectedIdle ? "idle" : "active")}", () => boxes[box - 1].IsIdle == expectedIdle);
|
||||
}
|
||||
|
||||
private void waitForAllIdle()
|
||||
{
|
||||
AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using static osu.Game.Tests.Visual.Components.TestScenePreviewTrackManager.TestPreviewTrackManager;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Components
|
||||
{
|
||||
@ -34,6 +35,7 @@ namespace osu.Game.Tests.Visual.Components
|
||||
PreviewTrack track = null;
|
||||
|
||||
AddStep("get track", () => track = getOwnedTrack());
|
||||
AddUntilStep("wait loaded", () => track.IsLoaded);
|
||||
AddStep("start", () => track.Start());
|
||||
AddAssert("started", () => track.IsRunning);
|
||||
AddStep("stop", () => track.Stop());
|
||||
@ -52,10 +54,15 @@ namespace osu.Game.Tests.Visual.Components
|
||||
track2 = getOwnedTrack();
|
||||
});
|
||||
|
||||
AddUntilStep("wait loaded", () => track1.IsLoaded && track2.IsLoaded);
|
||||
|
||||
AddStep("start track 1", () => track1.Start());
|
||||
AddStep("start track 2", () => track2.Start());
|
||||
AddAssert("track 1 stopped", () => !track1.IsRunning);
|
||||
AddAssert("track 2 started", () => track2.IsRunning);
|
||||
AddStep("start track 1", () => track1.Start());
|
||||
AddAssert("track 2 stopped", () => !track2.IsRunning);
|
||||
AddAssert("track 1 started", () => track1.IsRunning);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -64,6 +71,7 @@ namespace osu.Game.Tests.Visual.Components
|
||||
PreviewTrack track = null;
|
||||
|
||||
AddStep("get track", () => track = getOwnedTrack());
|
||||
AddUntilStep("wait loaded", () => track.IsLoaded);
|
||||
AddStep("start", () => track.Start());
|
||||
AddStep("stop by owner", () => trackManager.StopAnyPlaying(this));
|
||||
AddAssert("stopped", () => !track.IsRunning);
|
||||
@ -76,6 +84,7 @@ namespace osu.Game.Tests.Visual.Components
|
||||
PreviewTrack track = null;
|
||||
|
||||
AddStep("get track", () => Add(owner = new TestTrackOwner(track = getTrack())));
|
||||
AddUntilStep("wait loaded", () => track.IsLoaded);
|
||||
AddStep("start", () => track.Start());
|
||||
AddStep("attempt stop", () => trackManager.StopAnyPlaying(this));
|
||||
AddAssert("not stopped", () => track.IsRunning);
|
||||
@ -83,22 +92,46 @@ namespace osu.Game.Tests.Visual.Components
|
||||
AddAssert("stopped", () => !track.IsRunning);
|
||||
}
|
||||
|
||||
private PreviewTrack getTrack() => trackManager.Get(null);
|
||||
[Test]
|
||||
public void TestNonPresentTrack()
|
||||
{
|
||||
TestPreviewTrack track = null;
|
||||
|
||||
private PreviewTrack getOwnedTrack()
|
||||
AddStep("get non-present track", () =>
|
||||
{
|
||||
Add(new TestTrackOwner(track = getTrack()));
|
||||
track.Alpha = 0;
|
||||
});
|
||||
AddUntilStep("wait loaded", () => track.IsLoaded);
|
||||
AddStep("start", () => track.Start());
|
||||
AddStep("seek to end", () => track.Track.Seek(track.Track.Length));
|
||||
AddAssert("track stopped", () => !track.IsRunning);
|
||||
}
|
||||
|
||||
private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null);
|
||||
|
||||
private TestPreviewTrack getOwnedTrack()
|
||||
{
|
||||
var track = getTrack();
|
||||
|
||||
Add(track);
|
||||
LoadComponentAsync(track, Add);
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
private class TestTrackOwner : CompositeDrawable, IPreviewTrackOwner
|
||||
{
|
||||
private readonly PreviewTrack track;
|
||||
|
||||
public TestTrackOwner(PreviewTrack track)
|
||||
{
|
||||
AddInternal(track);
|
||||
this.track = track;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
LoadComponentAsync(track, AddInternal);
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
@ -109,18 +142,23 @@ namespace osu.Game.Tests.Visual.Components
|
||||
}
|
||||
}
|
||||
|
||||
private class TestPreviewTrackManager : PreviewTrackManager
|
||||
public class TestPreviewTrackManager : PreviewTrackManager
|
||||
{
|
||||
protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) => new TestPreviewTrack(beatmapSetInfo, trackManager);
|
||||
protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore);
|
||||
|
||||
protected class TestPreviewTrack : TrackManagerPreviewTrack
|
||||
public class TestPreviewTrack : TrackManagerPreviewTrack
|
||||
{
|
||||
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager)
|
||||
private readonly ITrackStore trackManager;
|
||||
|
||||
public new Track Track => base.Track;
|
||||
|
||||
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackManager)
|
||||
: base(beatmapSetInfo, trackManager)
|
||||
{
|
||||
this.trackManager = trackManager;
|
||||
}
|
||||
|
||||
protected override Track GetTrack() => new TrackVirtual { Length = 100000 };
|
||||
protected override Track GetTrack() => trackManager.GetVirtual(100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,20 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Edit.Compose;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneEditorCompose : EditorClockTestScene
|
||||
public class TestSceneComposeScreen : EditorClockTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ComposeScreen) };
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, Clock);
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
Child = new ComposeScreen();
|
||||
}
|
||||
}
|
171
osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
Normal file
171
osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
public class TestSceneDistanceSnapGrid : EditorClockTestScene
|
||||
{
|
||||
private const double beat_length = 100;
|
||||
private static readonly Vector2 grid_position = new Vector2(512, 384);
|
||||
|
||||
[Cached(typeof(IEditorBeatmap))]
|
||||
private readonly EditorBeatmap<OsuHitObject> editorBeatmap;
|
||||
|
||||
[Cached(typeof(IDistanceSnapProvider))]
|
||||
private readonly SnapProvider snapProvider = new SnapProvider();
|
||||
|
||||
public TestSceneDistanceSnapGrid()
|
||||
{
|
||||
editorBeatmap = new EditorBeatmap<OsuHitObject>(new OsuBeatmap());
|
||||
editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.SlateGray
|
||||
},
|
||||
new TestDistanceSnapGrid(new HitObject(), grid_position)
|
||||
};
|
||||
});
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
[TestCase(4)]
|
||||
[TestCase(6)]
|
||||
[TestCase(8)]
|
||||
[TestCase(12)]
|
||||
[TestCase(16)]
|
||||
public void TestBeatDivisor(int divisor)
|
||||
{
|
||||
AddStep($"set beat divisor = {divisor}", () => BeatDivisor.Value = divisor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLimitedDistance()
|
||||
{
|
||||
AddStep("create limited grid", () =>
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.SlateGray
|
||||
},
|
||||
new TestDistanceSnapGrid(new HitObject(), grid_position, new HitObject { StartTime = 100 })
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private class TestDistanceSnapGrid : DistanceSnapGrid
|
||||
{
|
||||
public new float DistanceSpacing => base.DistanceSpacing;
|
||||
|
||||
public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition, HitObject nextHitObject = null)
|
||||
: base(hitObject, nextHitObject, centrePosition)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateContent(Vector2 centrePosition)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(5),
|
||||
Position = centrePosition
|
||||
});
|
||||
|
||||
int beatIndex = 0;
|
||||
|
||||
for (float s = centrePosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(5, 10),
|
||||
Position = new Vector2(s, centrePosition.Y),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
});
|
||||
}
|
||||
|
||||
beatIndex = 0;
|
||||
|
||||
for (float s = centrePosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(5, 10),
|
||||
Position = new Vector2(s, centrePosition.Y),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
});
|
||||
}
|
||||
|
||||
beatIndex = 0;
|
||||
|
||||
for (float s = centrePosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(10, 5),
|
||||
Position = new Vector2(centrePosition.X, s),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
});
|
||||
}
|
||||
|
||||
beatIndex = 0;
|
||||
|
||||
for (float s = centrePosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(10, 5),
|
||||
Position = new Vector2(centrePosition.X, s),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override (Vector2 position, double time) GetSnappedPosition(Vector2 screenSpacePosition)
|
||||
=> (Vector2.Zero, 0);
|
||||
}
|
||||
|
||||
private class SnapProvider : IDistanceSnapProvider
|
||||
{
|
||||
public (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time) => (position, time);
|
||||
|
||||
public float GetBeatSnapDistanceAt(double referenceTime) => 10;
|
||||
|
||||
public float DurationToDistance(double referenceTime, double duration) => (float)duration;
|
||||
|
||||
public double DistanceToDuration(double referenceTime, float distance) => distance;
|
||||
|
||||
public double GetSnappedDurationFromDistance(double referenceTime, float distance) => 0;
|
||||
|
||||
public float GetSnappedDistanceFromDistance(double referenceTime, float distance) => 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,13 +5,14 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -30,9 +31,9 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
Beatmap.Value = new WaveformTestBeatmap();
|
||||
Beatmap.Value = new WaveformTestBeatmap(audio);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -100,7 +101,7 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private class StartStopButton : Button
|
||||
private class StartStopButton : OsuButton
|
||||
{
|
||||
private IAdjustableClock adjustableClock;
|
||||
private bool started;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -29,18 +28,7 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
var testBeatmap = new Beatmap
|
||||
{
|
||||
ControlPointInfo = new ControlPointInfo
|
||||
{
|
||||
TimingPoints =
|
||||
{
|
||||
new TimingControlPoint { Time = 0, BeatLength = 200 },
|
||||
new TimingControlPoint { Time = 100, BeatLength = 400 },
|
||||
new TimingControlPoint { Time = 175, BeatLength = 800 },
|
||||
new TimingControlPoint { Time = 350, BeatLength = 200 },
|
||||
new TimingControlPoint { Time = 450, BeatLength = 100 },
|
||||
new TimingControlPoint { Time = 500, BeatLength = 307.69230769230802 }
|
||||
}
|
||||
},
|
||||
ControlPointInfo = new ControlPointInfo(),
|
||||
HitObjects =
|
||||
{
|
||||
new HitCircle { StartTime = 0 },
|
||||
@ -48,7 +36,14 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
}
|
||||
};
|
||||
|
||||
Beatmap.Value = new TestWorkingBeatmap(testBeatmap, Clock);
|
||||
testBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 200 });
|
||||
testBeatmap.ControlPointInfo.Add(100, new TimingControlPoint { BeatLength = 400 });
|
||||
testBeatmap.ControlPointInfo.Add(175, new TimingControlPoint { BeatLength = 800 });
|
||||
testBeatmap.ControlPointInfo.Add(350, new TimingControlPoint { BeatLength = 200 });
|
||||
testBeatmap.ControlPointInfo.Add(450, new TimingControlPoint { BeatLength = 100 });
|
||||
testBeatmap.ControlPointInfo.Add(500, new TimingControlPoint { BeatLength = 307.69230769230802 });
|
||||
|
||||
Beatmap.Value = CreateWorkingBeatmap(testBeatmap);
|
||||
|
||||
Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock };
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
@ -21,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, null);
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
|
||||
Add(new SummaryTimeline
|
||||
{
|
||||
|
@ -16,16 +16,13 @@ using osu.Game.Rulesets.Osu.Edit;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Edit.Compose;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
[TestFixture]
|
||||
[Cached(Type = typeof(IPlacementHandler))]
|
||||
public class TestSceneHitObjectComposer : OsuTestScene, IPlacementHandler
|
||||
public class TestSceneHitObjectComposer : EditorClockTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@ -40,12 +37,10 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
typeof(HitCirclePlacementBlueprint),
|
||||
};
|
||||
|
||||
private HitObjectComposer composer;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Beatmap.Value = new TestWorkingBeatmap(new Beatmap
|
||||
Beatmap.Value = CreateWorkingBeatmap(new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@ -68,15 +63,7 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
Dependencies.CacheAs<IAdjustableClock>(clock);
|
||||
Dependencies.CacheAs<IFrameBasedClock>(clock);
|
||||
|
||||
Child = composer = new OsuHitObjectComposer(new OsuRuleset());
|
||||
Child = new OsuHitObjectComposer(new OsuRuleset());
|
||||
}
|
||||
|
||||
public void BeginPlacement(HitObject hitObject)
|
||||
{
|
||||
}
|
||||
|
||||
public void EndPlacement(HitObject hitObject) => composer.Add(hitObject);
|
||||
|
||||
public void Delete(HitObject hitObject) => composer.Remove(hitObject);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Edit.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
Size = new Vector2(200, 100)
|
||||
};
|
||||
|
||||
Beatmap.Value = new TestWorkingBeatmap(new Beatmap(), Clock);
|
||||
Beatmap.Value = CreateWorkingBeatmap(new Beatmap());
|
||||
|
||||
Child = playback;
|
||||
}
|
||||
|
35
osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs
Normal file
35
osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Edit.Timing;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneTimingScreen : EditorClockTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ControlPointTable),
|
||||
typeof(ControlPointSettings),
|
||||
typeof(Section<>),
|
||||
typeof(TimingSection),
|
||||
typeof(EffectSection),
|
||||
typeof(SampleSection),
|
||||
typeof(DifficultySection),
|
||||
typeof(RowAttribute)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
Child = new TimingScreen();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
@ -10,6 +11,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
@ -20,9 +22,9 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
private WorkingBeatmap waveformBeatmap;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
waveformBeatmap = new WaveformTestBeatmap();
|
||||
waveformBeatmap = new WaveformTestBeatmap(audio);
|
||||
}
|
||||
|
||||
[TestCase(1f)]
|
||||
@ -91,7 +93,7 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
Child = graph = new TestWaveformGraph
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Waveform = new DummyWorkingBeatmap().Waveform,
|
||||
Waveform = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).Waveform,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private void loadPlayerWithBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
Beatmap.Value = new TestWorkingBeatmap(beatmap, Clock);
|
||||
Beatmap.Value = new TestWorkingBeatmap(beatmap);
|
||||
|
||||
LoadScreen(player = new LeadInPlayer());
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
@ -12,6 +13,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Description("Player instantiated with an autoplay mod.")]
|
||||
public class TestSceneAutoplay : AllPlayersTestScene
|
||||
{
|
||||
private ClockBackedTestWorkingBeatmap.TrackVirtualManual track;
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||
@ -21,7 +24,18 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
protected override void AddCheckSteps()
|
||||
{
|
||||
AddUntilStep("score above zero", () => ((ScoreAccessiblePlayer)Player).ScoreProcessor.TotalScore.Value > 0);
|
||||
AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
|
||||
AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
|
||||
AddStep("rewind", () => track.Seek(-10000));
|
||||
AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
}
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
var working = base.CreateWorkingBeatmap(beatmap);
|
||||
|
||||
track = (ClockBackedTestWorkingBeatmap.TrackVirtualManual)working.Track;
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
private class ScoreAccessiblePlayer : TestPlayer
|
||||
@ -29,6 +43,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||
|
||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||
|
||||
public ScoreAccessiblePlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
|
119
osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
Normal file
119
osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneBarHitErrorMeter : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(HitErrorMeter),
|
||||
};
|
||||
|
||||
private HitErrorMeter meter;
|
||||
private HitErrorMeter meter2;
|
||||
private HitWindows hitWindows;
|
||||
|
||||
public TestSceneBarHitErrorMeter()
|
||||
{
|
||||
recreateDisplay(new OsuHitWindows(), 5);
|
||||
|
||||
AddRepeatStep("New random judgement", () => newJudgement(), 40);
|
||||
|
||||
AddRepeatStep("New max negative", () => newJudgement(-hitWindows.WindowFor(HitResult.Meh)), 20);
|
||||
AddRepeatStep("New max positive", () => newJudgement(hitWindows.WindowFor(HitResult.Meh)), 20);
|
||||
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOsu()
|
||||
{
|
||||
AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1));
|
||||
AddStep("OD 10", () => recreateDisplay(new OsuHitWindows(), 10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTaiko()
|
||||
{
|
||||
AddStep("OD 1", () => recreateDisplay(new TaikoHitWindows(), 1));
|
||||
AddStep("OD 10", () => recreateDisplay(new TaikoHitWindows(), 10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMania()
|
||||
{
|
||||
AddStep("OD 1", () => recreateDisplay(new ManiaHitWindows(), 1));
|
||||
AddStep("OD 10", () => recreateDisplay(new ManiaHitWindows(), 10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCatch()
|
||||
{
|
||||
AddStep("OD 1", () => recreateDisplay(new CatchHitWindows(), 1));
|
||||
AddStep("OD 10", () => recreateDisplay(new CatchHitWindows(), 10));
|
||||
}
|
||||
|
||||
private void recreateDisplay(HitWindows hitWindows, float overallDifficulty)
|
||||
{
|
||||
this.hitWindows = hitWindows;
|
||||
|
||||
hitWindows?.SetDifficulty(overallDifficulty);
|
||||
|
||||
Clear();
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Direction = FillDirection.Vertical,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new[]
|
||||
{
|
||||
new SpriteText { Text = $@"Great: {hitWindows?.WindowFor(HitResult.Great)}" },
|
||||
new SpriteText { Text = $@"Good: {hitWindows?.WindowFor(HitResult.Good)}" },
|
||||
new SpriteText { Text = $@"Meh: {hitWindows?.WindowFor(HitResult.Meh)}" },
|
||||
}
|
||||
});
|
||||
|
||||
Add(meter = new BarHitErrorMeter(hitWindows, true)
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
});
|
||||
|
||||
Add(meter2 = new BarHitErrorMeter(hitWindows, false)
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
});
|
||||
}
|
||||
|
||||
private void newJudgement(double offset = 0)
|
||||
{
|
||||
var judgement = new JudgementResult(new HitObject(), new Judgement())
|
||||
{
|
||||
TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset,
|
||||
Type = HitResult.Perfect,
|
||||
};
|
||||
|
||||
meter.OnNewJudgement(judgement);
|
||||
meter2.OnNewJudgement(judgement);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT 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.Timing;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
@ -11,78 +14,172 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[TestFixture]
|
||||
public class TestSceneBreakOverlay : OsuTestScene
|
||||
{
|
||||
private readonly BreakOverlay breakOverlay;
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(BreakOverlay),
|
||||
};
|
||||
|
||||
private readonly TestBreakOverlay breakOverlay;
|
||||
|
||||
private readonly IReadOnlyList<BreakPeriod> testBreaks = new List<BreakPeriod>
|
||||
{
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = 1000,
|
||||
EndTime = 5000,
|
||||
},
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = 6000,
|
||||
EndTime = 13500,
|
||||
},
|
||||
};
|
||||
|
||||
public TestSceneBreakOverlay()
|
||||
{
|
||||
Child = breakOverlay = new BreakOverlay(true);
|
||||
|
||||
AddStep("2s break", () => startBreak(2000));
|
||||
AddStep("5s break", () => startBreak(5000));
|
||||
AddStep("10s break", () => startBreak(10000));
|
||||
AddStep("15s break", () => startBreak(15000));
|
||||
AddStep("2s, 2s", startMultipleBreaks);
|
||||
AddStep("0.5s, 0.7s, 1s, 2s", startAnotherMultipleBreaks);
|
||||
Add(breakOverlay = new TestBreakOverlay(true));
|
||||
}
|
||||
|
||||
private void startBreak(double duration)
|
||||
[Test]
|
||||
public void TestShowBreaks()
|
||||
{
|
||||
breakOverlay.Breaks = new List<BreakPeriod>
|
||||
setClock(false);
|
||||
|
||||
addShowBreakStep(2);
|
||||
addShowBreakStep(5);
|
||||
addShowBreakStep(15);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoEffectsBreak()
|
||||
{
|
||||
var shortBreak = new BreakPeriod { EndTime = 500 };
|
||||
|
||||
setClock(true);
|
||||
loadBreaksStep("short break", new[] { shortBreak });
|
||||
|
||||
addBreakSeeks(shortBreak, false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleBreaks()
|
||||
{
|
||||
setClock(true);
|
||||
loadBreaksStep("multiple breaks", testBreaks);
|
||||
|
||||
foreach (var b in testBreaks)
|
||||
addBreakSeeks(b, false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRewindBreaks()
|
||||
{
|
||||
setClock(true);
|
||||
loadBreaksStep("multiple breaks", testBreaks);
|
||||
|
||||
foreach (var b in testBreaks.Reverse())
|
||||
addBreakSeeks(b, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSkipBreaks()
|
||||
{
|
||||
setClock(true);
|
||||
loadBreaksStep("multiple breaks", testBreaks);
|
||||
|
||||
seekAndAssertBreak("seek to break start", testBreaks[1].StartTime, true);
|
||||
AddAssert("is skipped to break #2", () => breakOverlay.CurrentBreakIndex == 1);
|
||||
|
||||
seekAndAssertBreak("seek to break middle", testBreaks[1].StartTime + testBreaks[1].Duration / 2, true);
|
||||
seekAndAssertBreak("seek to break end", testBreaks[1].EndTime, false);
|
||||
seekAndAssertBreak("seek to break after end", testBreaks[1].EndTime + 500, false);
|
||||
}
|
||||
|
||||
private void addShowBreakStep(double seconds)
|
||||
{
|
||||
AddStep($"show '{seconds}s' break", () => breakOverlay.Breaks = new List<BreakPeriod>
|
||||
{
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = Clock.CurrentTime,
|
||||
EndTime = Clock.CurrentTime + duration,
|
||||
EndTime = Clock.CurrentTime + seconds * 1000,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void startMultipleBreaks()
|
||||
private void setClock(bool useManual)
|
||||
{
|
||||
double currentTime = Clock.CurrentTime;
|
||||
|
||||
breakOverlay.Breaks = new List<BreakPeriod>
|
||||
{
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = currentTime,
|
||||
EndTime = currentTime + 2000,
|
||||
},
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = currentTime + 4000,
|
||||
EndTime = currentTime + 6000,
|
||||
}
|
||||
};
|
||||
AddStep($"set {(useManual ? "manual" : "realtime")} clock", () => breakOverlay.SwitchClock(useManual));
|
||||
}
|
||||
|
||||
private void startAnotherMultipleBreaks()
|
||||
private void loadBreaksStep(string breakDescription, IReadOnlyList<BreakPeriod> breaks)
|
||||
{
|
||||
double currentTime = Clock.CurrentTime;
|
||||
AddStep($"load {breakDescription}", () => breakOverlay.Breaks = breaks);
|
||||
seekAndAssertBreak("seek back to 0", 0, false);
|
||||
}
|
||||
|
||||
breakOverlay.Breaks = new List<BreakPeriod>
|
||||
private void addBreakSeeks(BreakPeriod b, bool isReversed)
|
||||
{
|
||||
if (isReversed)
|
||||
{
|
||||
new BreakPeriod // Duration is less than 650 - too short to appear
|
||||
{
|
||||
StartTime = currentTime,
|
||||
EndTime = currentTime + 500,
|
||||
},
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = currentTime + 1500,
|
||||
EndTime = currentTime + 2200,
|
||||
},
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = currentTime + 3200,
|
||||
EndTime = currentTime + 4200,
|
||||
},
|
||||
new BreakPeriod
|
||||
{
|
||||
StartTime = currentTime + 5200,
|
||||
EndTime = currentTime + 7200,
|
||||
}
|
||||
};
|
||||
seekAndAssertBreak("seek to break after end", b.EndTime + 500, false);
|
||||
seekAndAssertBreak("seek to break end", b.EndTime, false);
|
||||
seekAndAssertBreak("seek to break middle", b.StartTime + b.Duration / 2, b.HasEffect);
|
||||
seekAndAssertBreak("seek to break start", b.StartTime, b.HasEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
seekAndAssertBreak("seek to break start", b.StartTime, b.HasEffect);
|
||||
seekAndAssertBreak("seek to break middle", b.StartTime + b.Duration / 2, b.HasEffect);
|
||||
seekAndAssertBreak("seek to break end", b.EndTime, false);
|
||||
seekAndAssertBreak("seek to break after end", b.EndTime + 500, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void seekAndAssertBreak(string seekStepDescription, double time, bool shouldBeBreak)
|
||||
{
|
||||
AddStep(seekStepDescription, () => breakOverlay.ManualClockTime = time);
|
||||
AddAssert($"is{(!shouldBeBreak ? " not" : string.Empty)} break time", () =>
|
||||
{
|
||||
breakOverlay.ProgressTime();
|
||||
return breakOverlay.IsBreakTime.Value == shouldBeBreak;
|
||||
});
|
||||
}
|
||||
|
||||
private class TestBreakOverlay : BreakOverlay
|
||||
{
|
||||
private readonly FramedClock framedManualClock;
|
||||
private readonly ManualClock manualClock;
|
||||
private IFrameBasedClock originalClock;
|
||||
|
||||
public new int CurrentBreakIndex => base.CurrentBreakIndex;
|
||||
|
||||
public double ManualClockTime
|
||||
{
|
||||
get => manualClock.CurrentTime;
|
||||
set => manualClock.CurrentTime = value;
|
||||
}
|
||||
|
||||
public TestBreakOverlay(bool letterboxing)
|
||||
: base(letterboxing)
|
||||
{
|
||||
framedManualClock = new FramedClock(manualClock = new ManualClock());
|
||||
ProcessCustomClock = false;
|
||||
}
|
||||
|
||||
public void ProgressTime()
|
||||
{
|
||||
framedManualClock.ProcessFrame();
|
||||
Update();
|
||||
}
|
||||
|
||||
public void SwitchClock(bool setManual) => Clock = setManual ? framedManualClock : originalClock;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
originalClock = Clock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,334 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneDrawableScrollingRuleset : OsuTestScene
|
||||
{
|
||||
/// <summary>
|
||||
/// The amount of time visible by the "view window" of the playfield.
|
||||
/// All hitobjects added through <see cref="createBeatmap"/> are spaced apart by this value, such that for a beat length of 1000,
|
||||
/// there will be at most 2 hitobjects visible in the "view window".
|
||||
/// </summary>
|
||||
private const double time_range = 1000;
|
||||
|
||||
private readonly ManualClock testClock = new ManualClock();
|
||||
private TestDrawableScrollingRuleset drawableRuleset;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() => testClock.CurrentTime = 0);
|
||||
|
||||
[Test]
|
||||
public void TestRelativeBeatLengthScaleSingleTimingPoint()
|
||||
{
|
||||
var beatmap = createBeatmap();
|
||||
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range / 2 });
|
||||
|
||||
createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true);
|
||||
|
||||
assertPosition(0, 0f);
|
||||
|
||||
// The single timing point is 1x speed relative to itself, such that the hitobject occurring time_range milliseconds later should appear
|
||||
// at the bottom of the view window regardless of the timing point's beat length
|
||||
assertPosition(1, 1f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRelativeBeatLengthScaleTimingPointBeyondEndDoesNotBecomeDominant()
|
||||
{
|
||||
var beatmap = createBeatmap();
|
||||
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range / 2 });
|
||||
beatmap.ControlPointInfo.Add(12000, new TimingControlPoint { BeatLength = time_range });
|
||||
beatmap.ControlPointInfo.Add(100000, new TimingControlPoint { BeatLength = time_range });
|
||||
|
||||
createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true);
|
||||
|
||||
assertPosition(0, 0f);
|
||||
assertPosition(1, 1f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRelativeBeatLengthScaleFromSecondTimingPoint()
|
||||
{
|
||||
var beatmap = createBeatmap();
|
||||
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range });
|
||||
beatmap.ControlPointInfo.Add(3 * time_range, new TimingControlPoint { BeatLength = time_range / 2 });
|
||||
|
||||
createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true);
|
||||
|
||||
// The first timing point should have a relative velocity of 2
|
||||
assertPosition(0, 0f);
|
||||
assertPosition(1, 0.5f);
|
||||
assertPosition(2, 1f);
|
||||
|
||||
// Move to the second timing point
|
||||
setTime(3 * time_range);
|
||||
assertPosition(3, 0f);
|
||||
|
||||
// As above, this is the timing point that is 1x speed relative to itself, so the hitobject occurring time_range milliseconds later should be at the bottom of the view window
|
||||
assertPosition(4, 1f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNonRelativeScale()
|
||||
{
|
||||
var beatmap = createBeatmap();
|
||||
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range });
|
||||
beatmap.ControlPointInfo.Add(3 * time_range, new TimingControlPoint { BeatLength = time_range / 2 });
|
||||
|
||||
createTest(beatmap);
|
||||
|
||||
assertPosition(0, 0f);
|
||||
assertPosition(1, 1);
|
||||
|
||||
// Move to the second timing point
|
||||
setTime(3 * time_range);
|
||||
assertPosition(3, 0f);
|
||||
|
||||
// For a beat length of 500, the view window of this timing point is elongated 2x (1000 / 500), such that the second hitobject is two TimeRanges away (offscreen)
|
||||
// To bring it on-screen, half TimeRange is added to the current time, bringing the second half of the view window into view, and the hitobject should appear at the bottom
|
||||
setTime(3 * time_range + time_range / 2);
|
||||
assertPosition(4, 1f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSliderMultiplierDoesNotAffectRelativeBeatLength()
|
||||
{
|
||||
var beatmap = createBeatmap();
|
||||
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range });
|
||||
beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2;
|
||||
|
||||
createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true);
|
||||
AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 5000);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
assertPosition(i, i / 5f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSliderMultiplierAffectsNonRelativeBeatLength()
|
||||
{
|
||||
var beatmap = createBeatmap();
|
||||
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range });
|
||||
beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2;
|
||||
|
||||
createTest(beatmap);
|
||||
AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 2000);
|
||||
|
||||
assertPosition(0, 0);
|
||||
assertPosition(1, 1);
|
||||
}
|
||||
|
||||
private void assertPosition(int index, float relativeY) => AddAssert($"hitobject {index} at {relativeY}",
|
||||
() => Precision.AlmostEquals(drawableRuleset.Playfield.AllHitObjects.ElementAt(index).DrawPosition.Y, drawableRuleset.Playfield.HitObjectContainer.DrawHeight * relativeY));
|
||||
|
||||
private void setTime(double time)
|
||||
{
|
||||
AddStep($"set time = {time}", () => testClock.CurrentTime = time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IBeatmap"/>, containing 10 hitobjects and user-provided timing points.
|
||||
/// The hitobjects are spaced <see cref="time_range"/> milliseconds apart.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IBeatmap"/>.</returns>
|
||||
private IBeatmap createBeatmap()
|
||||
{
|
||||
var beatmap = new Beatmap<HitObject> { BeatmapInfo = { Ruleset = new OsuRuleset().RulesetInfo } };
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
beatmap.HitObjects.Add(new HitObject { StartTime = i * time_range });
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
private void createTest(IBeatmap beatmap, Action<TestDrawableScrollingRuleset> overrideAction = null) => AddStep("create test", () =>
|
||||
{
|
||||
var ruleset = new TestScrollingRuleset();
|
||||
|
||||
drawableRuleset = (TestDrawableScrollingRuleset)ruleset.CreateDrawableRulesetWith(CreateWorkingBeatmap(beatmap), Array.Empty<Mod>());
|
||||
drawableRuleset.FrameStablePlayback = false;
|
||||
|
||||
overrideAction?.Invoke(drawableRuleset);
|
||||
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Height = 0.75f,
|
||||
Width = 400,
|
||||
Masking = true,
|
||||
Clock = new FramedClock(testClock),
|
||||
Child = drawableRuleset
|
||||
};
|
||||
});
|
||||
|
||||
#region Ruleset
|
||||
|
||||
private class TestScrollingRuleset : Ruleset
|
||||
{
|
||||
public TestScrollingRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type) => throw new NotImplementedException();
|
||||
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods) => new TestDrawableScrollingRuleset(this, beatmap, mods);
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap);
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||
|
||||
public override string Description { get; } = string.Empty;
|
||||
|
||||
public override string ShortName { get; } = string.Empty;
|
||||
}
|
||||
|
||||
private class TestDrawableScrollingRuleset : DrawableScrollingRuleset<TestHitObject>
|
||||
{
|
||||
public bool RelativeScaleBeatLengthsOverride { get; set; }
|
||||
|
||||
protected override bool RelativeScaleBeatLengths => RelativeScaleBeatLengthsOverride;
|
||||
|
||||
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
|
||||
|
||||
public new Bindable<double> TimeRange => base.TimeRange;
|
||||
|
||||
public TestDrawableScrollingRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
|
||||
: base(ruleset, beatmap, mods)
|
||||
{
|
||||
TimeRange.Value = time_range;
|
||||
}
|
||||
|
||||
public override DrawableHitObject<TestHitObject> CreateDrawableRepresentation(TestHitObject h) => new DrawableTestHitObject(h);
|
||||
|
||||
protected override PassThroughInputManager CreateInputManager() => new PassThroughInputManager();
|
||||
|
||||
protected override Playfield CreatePlayfield() => new TestPlayfield();
|
||||
}
|
||||
|
||||
private class TestPlayfield : ScrollingPlayfield
|
||||
{
|
||||
public TestPlayfield()
|
||||
{
|
||||
AddInternal(new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.2f,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = 150 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2,
|
||||
Colour = Color4.Green
|
||||
},
|
||||
HitObjectContainer
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class TestBeatmapConverter : BeatmapConverter<TestHitObject>
|
||||
{
|
||||
public TestBeatmapConverter(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<Type> ValidConversionTypes => new[] { typeof(HitObject) };
|
||||
|
||||
protected override IEnumerable<TestHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap)
|
||||
{
|
||||
yield return new TestHitObject
|
||||
{
|
||||
StartTime = original.StartTime,
|
||||
EndTime = (original as IHasEndTime)?.EndTime ?? (original.StartTime + 100)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HitObject
|
||||
|
||||
private class TestHitObject : HitObject, IHasEndTime
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
||||
public double Duration => EndTime - StartTime;
|
||||
}
|
||||
|
||||
private class DrawableTestHitObject : DrawableHitObject<TestHitObject>
|
||||
{
|
||||
public DrawableTestHitObject(TestHitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
Size = new Vector2(100, 25);
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.LightPink
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2,
|
||||
Colour = Color4.Red
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
50
osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
Normal file
50
osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneFailAnimation : AllPlayersTestScene
|
||||
{
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
Mods.Value = Array.Empty<Mod>();
|
||||
return new FailPlayer();
|
||||
}
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(AllPlayersTestScene),
|
||||
typeof(TestPlayer),
|
||||
typeof(Player),
|
||||
};
|
||||
|
||||
protected override void AddCheckSteps()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddUntilStep("wait for fail overlay", () => ((FailPlayer)Player).FailOverlay.State.Value == Visibility.Visible);
|
||||
}
|
||||
|
||||
private class FailPlayer : TestPlayer
|
||||
{
|
||||
public new FailOverlay FailOverlay => base.FailOverlay;
|
||||
|
||||
public FailPlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
ScoreProcessor.FailConditions += (_, __) => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs
Normal file
44
osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneFailJudgement : AllPlayersTestScene
|
||||
{
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
Mods.Value = Array.Empty<Mod>();
|
||||
return new FailPlayer();
|
||||
}
|
||||
|
||||
protected override void AddCheckSteps()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddUntilStep("wait for multiple judged objects", () => ((FailPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.Count(h => h.AllJudged) > 1);
|
||||
AddAssert("total judgements == 1", () => ((FailPlayer)Player).ScoreProcessor.JudgedHits == 1);
|
||||
}
|
||||
|
||||
private class FailPlayer : TestPlayer
|
||||
{
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
|
||||
public FailPlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
ScoreProcessor.FailConditions += (_, __) => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,12 +3,13 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
@ -29,57 +30,118 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase game)
|
||||
{
|
||||
Child = globalActionContainer = new GlobalActionContainer(game)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
pauseOverlay = new PauseOverlay
|
||||
{
|
||||
OnResume = () => Logger.Log(@"Resume"),
|
||||
OnRetry = () => Logger.Log(@"Retry"),
|
||||
OnQuit = () => Logger.Log(@"Quit"),
|
||||
},
|
||||
failOverlay = new FailOverlay
|
||||
Child = globalActionContainer = new GlobalActionContainer(game);
|
||||
}
|
||||
|
||||
{
|
||||
OnRetry = () => Logger.Log(@"Retry"),
|
||||
OnQuit = () => Logger.Log(@"Quit"),
|
||||
}
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
globalActionContainer.Children = new Drawable[]
|
||||
{
|
||||
pauseOverlay = new PauseOverlay
|
||||
{
|
||||
OnResume = () => Logger.Log(@"Resume"),
|
||||
OnRetry = () => Logger.Log(@"Retry"),
|
||||
OnQuit = () => Logger.Log(@"Quit"),
|
||||
},
|
||||
failOverlay = new FailOverlay
|
||||
|
||||
{
|
||||
OnRetry = () => Logger.Log(@"Retry"),
|
||||
OnQuit = () => Logger.Log(@"Quit"),
|
||||
}
|
||||
};
|
||||
|
||||
InputManager.MoveMouseTo(Vector2.Zero);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestAdjustRetryCount()
|
||||
{
|
||||
showOverlay();
|
||||
|
||||
var retryCount = 0;
|
||||
|
||||
AddStep("Add retry", () =>
|
||||
AddRepeatStep("Add retry", () =>
|
||||
{
|
||||
retryCount++;
|
||||
pauseOverlay.Retries = failOverlay.Retries = retryCount;
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
|
||||
AddToggleStep("Toggle pause overlay", t => pauseOverlay.ToggleVisibility());
|
||||
AddToggleStep("Toggle fail overlay", t => failOverlay.ToggleVisibility());
|
||||
/// <summary>
|
||||
/// Tests that pressing enter after an overlay shows doesn't trigger an event because a selection hasn't occurred.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestEnterWithoutSelection()
|
||||
{
|
||||
showOverlay();
|
||||
|
||||
testHideResets();
|
||||
AddStep("Press select", () => press(GlobalAction.Select));
|
||||
AddAssert("Overlay still open", () => pauseOverlay.State.Value == Visibility.Visible);
|
||||
}
|
||||
|
||||
testEnterWithoutSelection();
|
||||
testKeyUpFromInitial();
|
||||
testKeyDownFromInitial();
|
||||
testKeyUpWrapping();
|
||||
testKeyDownWrapping();
|
||||
/// <summary>
|
||||
/// Tests that pressing the up arrow from the initial state selects the last button.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestKeyUpFromInitial()
|
||||
{
|
||||
showOverlay();
|
||||
|
||||
testMouseSelectionAfterKeySelection();
|
||||
testKeySelectionAfterMouseSelection();
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().Selected.Value);
|
||||
}
|
||||
|
||||
testMouseDeselectionResets();
|
||||
/// <summary>
|
||||
/// Tests that pressing the down arrow from the initial state selects the first button.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestKeyDownFromInitial()
|
||||
{
|
||||
showOverlay();
|
||||
|
||||
testClickSelection();
|
||||
testEnterKeySelection();
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing the up arrow repeatedly causes the selected button to wrap correctly.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestKeyUpWrapping()
|
||||
{
|
||||
AddStep("Show overlay", () => failOverlay.Show());
|
||||
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing the down arrow repeatedly causes the selected button to wrap correctly.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestKeyDownWrapping()
|
||||
{
|
||||
AddStep("Show overlay", () => failOverlay.Show());
|
||||
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that hiding the overlay after hovering a button will reset the overlay to the initial state with no buttons selected.
|
||||
/// </summary>
|
||||
private void testHideResets()
|
||||
[Test]
|
||||
public void TestHideResets()
|
||||
{
|
||||
AddStep("Show overlay", () => failOverlay.Show());
|
||||
|
||||
@ -90,141 +152,78 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing enter after an overlay shows doesn't trigger an event because a selection hasn't occurred.
|
||||
/// Tests that entering menu with cursor initially on button doesn't selects it immediately.
|
||||
/// This is to allow for stable keyboard navigation.
|
||||
/// </summary>
|
||||
private void testEnterWithoutSelection()
|
||||
[Test]
|
||||
public void TestInitialButtonHover()
|
||||
{
|
||||
AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
showOverlay();
|
||||
|
||||
AddStep("Press select", () => press(GlobalAction.Select));
|
||||
AddAssert("Overlay still open", () => pauseOverlay.State == Visibility.Visible);
|
||||
AddStep("Hover first button", () => InputManager.MoveMouseTo(getButton(0)));
|
||||
|
||||
AddStep("Hide overlay", () => pauseOverlay.Hide());
|
||||
}
|
||||
showOverlay();
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing the up arrow from the initial state selects the last button.
|
||||
/// </summary>
|
||||
private void testKeyUpFromInitial()
|
||||
{
|
||||
AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
AddAssert("First button not selected", () => !getButton(0).Selected.Value);
|
||||
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().Selected.Value);
|
||||
AddStep("Move slightly", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(1)));
|
||||
|
||||
AddStep("Hide overlay", () => pauseOverlay.Hide());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing the down arrow from the initial state selects the first button.
|
||||
/// </summary>
|
||||
private void testKeyDownFromInitial()
|
||||
{
|
||||
AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected.Value);
|
||||
|
||||
AddStep("Hide overlay", () => pauseOverlay.Hide());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing the up arrow repeatedly causes the selected button to wrap correctly.
|
||||
/// </summary>
|
||||
private void testKeyUpWrapping()
|
||||
{
|
||||
AddStep("Show overlay", () => failOverlay.Show());
|
||||
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
|
||||
AddStep("Hide overlay", () => failOverlay.Hide());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing the down arrow repeatedly causes the selected button to wrap correctly.
|
||||
/// </summary>
|
||||
private void testKeyDownWrapping()
|
||||
{
|
||||
AddStep("Show overlay", () => failOverlay.Show());
|
||||
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
|
||||
AddStep("Hide overlay", () => failOverlay.Hide());
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that hovering a button that was previously selected with the keyboard correctly selects the new button and deselects the previous button.
|
||||
/// </summary>
|
||||
private void testMouseSelectionAfterKeySelection()
|
||||
[Test]
|
||||
public void TestMouseSelectionAfterKeySelection()
|
||||
{
|
||||
AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
|
||||
var secondButton = pauseOverlay.Buttons.Skip(1).First();
|
||||
showOverlay();
|
||||
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(secondButton));
|
||||
AddAssert("First button not selected", () => !pauseOverlay.Buttons.First().Selected.Value);
|
||||
AddAssert("Second button selected", () => secondButton.Selected.Value);
|
||||
|
||||
AddStep("Hide overlay", () => pauseOverlay.Hide());
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||
AddAssert("First button not selected", () => !getButton(0).Selected.Value);
|
||||
AddAssert("Second button selected", () => getButton(1).Selected.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing a key after selecting a button with a hover event correctly selects a new button and deselects the previous button.
|
||||
/// </summary>
|
||||
private void testKeySelectionAfterMouseSelection()
|
||||
[Test]
|
||||
public void TestKeySelectionAfterMouseSelection()
|
||||
{
|
||||
AddStep("Show overlay", () =>
|
||||
{
|
||||
pauseOverlay.Show();
|
||||
InputManager.MoveMouseTo(Vector2.Zero);
|
||||
});
|
||||
|
||||
var secondButton = pauseOverlay.Buttons.Skip(1).First();
|
||||
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(secondButton));
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||
AddStep("Up arrow", () => press(Key.Up));
|
||||
AddAssert("Second button not selected", () => !secondButton.Selected.Value);
|
||||
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected.Value);
|
||||
|
||||
AddStep("Hide overlay", () => pauseOverlay.Hide());
|
||||
AddAssert("Second button not selected", () => !getButton(1).Selected.Value);
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that deselecting with the mouse by losing hover will reset the overlay to the initial state.
|
||||
/// </summary>
|
||||
private void testMouseDeselectionResets()
|
||||
[Test]
|
||||
public void TestMouseDeselectionResets()
|
||||
{
|
||||
AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
showOverlay();
|
||||
|
||||
var secondButton = pauseOverlay.Buttons.Skip(1).First();
|
||||
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(secondButton));
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||
AddStep("Unhover second button", () => InputManager.MoveMouseTo(Vector2.Zero));
|
||||
AddStep("Down arrow", () => press(Key.Down));
|
||||
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected.Value); // Initial state condition
|
||||
|
||||
AddStep("Hide overlay", () => pauseOverlay.Hide());
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value); // Initial state condition
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that clicking on a button correctly causes a click event for that button.
|
||||
/// </summary>
|
||||
private void testClickSelection()
|
||||
[Test]
|
||||
public void TestClickSelection()
|
||||
{
|
||||
AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
|
||||
var retryButton = pauseOverlay.Buttons.Skip(1).First();
|
||||
showOverlay();
|
||||
|
||||
bool triggered = false;
|
||||
AddStep("Click retry button", () =>
|
||||
@ -232,20 +231,21 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
var lastAction = pauseOverlay.OnRetry;
|
||||
pauseOverlay.OnRetry = () => triggered = true;
|
||||
|
||||
retryButton.Click();
|
||||
getButton(1).Click();
|
||||
pauseOverlay.OnRetry = lastAction;
|
||||
});
|
||||
|
||||
AddAssert("Action was triggered", () => triggered);
|
||||
AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden);
|
||||
AddAssert("Overlay is closed", () => pauseOverlay.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that pressing the enter key with a button selected correctly causes a click event for that button.
|
||||
/// </summary>
|
||||
private void testEnterKeySelection()
|
||||
[Test]
|
||||
public void TestEnterKeySelection()
|
||||
{
|
||||
AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
showOverlay();
|
||||
|
||||
AddStep("Select second button", () =>
|
||||
{
|
||||
@ -272,9 +272,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
return triggered;
|
||||
});
|
||||
AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden);
|
||||
AddAssert("Overlay is closed", () => pauseOverlay.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
private void showOverlay() => AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
|
||||
private DialogButton getButton(int index) => pauseOverlay.Buttons.Skip(index).First();
|
||||
|
||||
private void press(Key key)
|
||||
{
|
||||
InputManager.PressKey(key);
|
||||
|
116
osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
Normal file
116
osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneGameplayRewinding : PlayerTestScene
|
||||
{
|
||||
private RulesetExposingPlayer player => (RulesetExposingPlayer)Player;
|
||||
|
||||
[Resolved]
|
||||
private AudioManager audioManager { get; set; }
|
||||
|
||||
public TestSceneGameplayRewinding()
|
||||
: base(new OsuRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
private Track track;
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||
track = working.Track;
|
||||
return working;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoJudgementsOnRewind()
|
||||
{
|
||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
||||
addSeekStep(3000);
|
||||
AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
|
||||
AddUntilStep("key counter counted keys", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
|
||||
AddStep("clear results", () => player.AppliedResults.Clear());
|
||||
addSeekStep(0);
|
||||
AddAssert("none judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
|
||||
AddUntilStep("key counters reset", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
AddAssert("no results triggered", () => player.AppliedResults.Count == 0);
|
||||
}
|
||||
|
||||
private void addSeekStep(double time)
|
||||
{
|
||||
AddStep($"seek to {time}", () => track.Seek(time));
|
||||
|
||||
// Allow a few frames of lenience
|
||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||
}
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||
return new RulesetExposingPlayer();
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = { BaseDifficulty = { ApproachRate = 9 } },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
beatmap.HitObjects.Add(new HitCircle
|
||||
{
|
||||
Position = new Vector2(256, 192),
|
||||
StartTime = 1000 + 30 * i
|
||||
});
|
||||
}
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
private class RulesetExposingPlayer : Player
|
||||
{
|
||||
public readonly List<JudgementResult> AppliedResults = new List<JudgementResult>();
|
||||
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
|
||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||
|
||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||
|
||||
public new DrawableRuleset DrawableRuleset => base.DrawableRuleset;
|
||||
|
||||
public RulesetExposingPlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ScoreProcessor.NewJudgement += r => AppliedResults.Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
private bool exitAction;
|
||||
|
||||
protected override double TimePerAction => 100; // required for the early exit test, since hold-to-confirm delay is 200ms
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
|
@ -7,7 +7,6 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK.Input;
|
||||
|
||||
@ -25,14 +24,15 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public TestSceneKeyCounter()
|
||||
{
|
||||
KeyCounterKeyboard rewindTestKeyCounterKeyboard;
|
||||
KeyCounterKeyboard testCounter;
|
||||
|
||||
KeyCounterDisplay kc = new KeyCounterDisplay
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Children = new KeyCounter[]
|
||||
{
|
||||
rewindTestKeyCounterKeyboard = new KeyCounterKeyboard(Key.X),
|
||||
testCounter = new KeyCounterKeyboard(Key.X),
|
||||
new KeyCounterKeyboard(Key.X),
|
||||
new KeyCounterMouse(MouseButton.Left),
|
||||
new KeyCounterMouse(MouseButton.Right),
|
||||
@ -44,10 +44,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
Key key = (Key)((int)Key.A + RNG.Next(26));
|
||||
kc.Add(new KeyCounterKeyboard(key));
|
||||
});
|
||||
AddSliderStep("Fade time", 0, 200, 50, v => kc.FadeTime = v);
|
||||
|
||||
Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key;
|
||||
double time1 = 0;
|
||||
|
||||
AddStep($"Press {testKey} key", () =>
|
||||
{
|
||||
@ -55,48 +53,17 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
InputManager.ReleaseKey(testKey);
|
||||
});
|
||||
|
||||
AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 1);
|
||||
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1);
|
||||
|
||||
AddStep($"Press {testKey} key", () =>
|
||||
{
|
||||
InputManager.PressKey(testKey);
|
||||
InputManager.ReleaseKey(testKey);
|
||||
time1 = Clock.CurrentTime;
|
||||
});
|
||||
|
||||
AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 2);
|
||||
|
||||
IFrameBasedClock oldClock = null;
|
||||
|
||||
AddStep($"Rewind {testKey} counter once", () =>
|
||||
{
|
||||
oldClock = rewindTestKeyCounterKeyboard.Clock;
|
||||
rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(time1 - 10));
|
||||
});
|
||||
|
||||
AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 1);
|
||||
|
||||
AddStep($"Rewind {testKey} counter to zero", () => rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(0)));
|
||||
|
||||
AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 0);
|
||||
|
||||
AddStep("Restore clock", () => rewindTestKeyCounterKeyboard.Clock = oldClock);
|
||||
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2);
|
||||
|
||||
Add(kc);
|
||||
}
|
||||
|
||||
private class FixedClock : IClock
|
||||
{
|
||||
private readonly double time;
|
||||
|
||||
public FixedClock(double time)
|
||||
{
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public double CurrentTime => time;
|
||||
public double Rate => 1;
|
||||
public bool IsRunning => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,24 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
confirmClockRunning(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPauseWithResumeOverlay()
|
||||
{
|
||||
AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1);
|
||||
|
||||
pauseAndConfirm();
|
||||
|
||||
resume();
|
||||
confirmClockRunning(false);
|
||||
confirmPauseOverlayShown(false);
|
||||
|
||||
pauseAndConfirm();
|
||||
|
||||
AddUntilStep("resume overlay is not active", () => Player.DrawableRuleset.ResumeOverlay.State.Value == Visibility.Hidden);
|
||||
confirmPaused();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestResumeWithResumeOverlaySkipped()
|
||||
{
|
||||
@ -113,7 +131,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void TestPauseAfterFail()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddAssert("fail overlay shown", () => Player.FailOverlayVisible);
|
||||
AddUntilStep("fail overlay shown", () => Player.FailOverlayVisible);
|
||||
|
||||
confirmClockRunning(false);
|
||||
|
||||
@ -127,13 +145,62 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
exitAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitFromFailedGameplay()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddStep("exit", () => Player.Exit());
|
||||
|
||||
confirmExited();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestQuickRetryFromFailedGameplay()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddStep("quick retry", () => Player.GameplayClockContainer.OfType<HotkeyRetryOverlay>().First().Action?.Invoke());
|
||||
|
||||
confirmExited();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestQuickExitFromFailedGameplay()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddStep("quick exit", () => Player.GameplayClockContainer.OfType<HotkeyExitOverlay>().First().Action?.Invoke());
|
||||
|
||||
confirmExited();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitFromGameplay()
|
||||
{
|
||||
AddStep("exit", () => Player.Exit());
|
||||
|
||||
confirmExited();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestQuickExitFromGameplay()
|
||||
{
|
||||
AddStep("quick exit", () => Player.GameplayClockContainer.OfType<HotkeyExitOverlay>().First().Action?.Invoke());
|
||||
|
||||
confirmExited();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitViaHoldToExit()
|
||||
{
|
||||
AddStep("exit", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(Player.HUDOverlay.HoldToQuit.First(c => c is HoldToConfirmContainer));
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
});
|
||||
|
||||
confirmPaused();
|
||||
|
||||
AddStep("release", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
|
||||
exitAndConfirm();
|
||||
}
|
||||
|
||||
@ -144,6 +211,15 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
exitAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRestartAfterResume()
|
||||
{
|
||||
pauseAndConfirm();
|
||||
resumeAndConfirm();
|
||||
restart();
|
||||
confirmExited();
|
||||
}
|
||||
|
||||
private void pauseAndConfirm()
|
||||
{
|
||||
pause();
|
||||
@ -161,6 +237,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("player not exited", () => Player.IsCurrentScreen());
|
||||
AddStep("exit", () => Player.Exit());
|
||||
confirmExited();
|
||||
confirmNoTrackAdjustments();
|
||||
}
|
||||
|
||||
private void confirmPaused()
|
||||
@ -182,6 +259,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("player exited", () => !Player.IsCurrentScreen());
|
||||
}
|
||||
|
||||
private void confirmNoTrackAdjustments()
|
||||
{
|
||||
AddAssert("track has no adjustments", () => Beatmap.Value.Track.AggregateFrequency.Value == 1);
|
||||
}
|
||||
|
||||
private void restart() => AddStep("restart", () => Player.Restart());
|
||||
private void pause() => AddStep("pause", () => Player.Pause());
|
||||
private void resume() => AddStep("resume", () => Player.Resume());
|
||||
|
||||
@ -189,7 +272,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("pause overlay " + (isShown ? "shown" : "hidden"), () => Player.PauseOverlayVisible == isShown);
|
||||
|
||||
private void confirmClockRunning(bool isRunning) =>
|
||||
AddAssert("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.GameplayClock.IsRunning == isRunning);
|
||||
AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.GameplayClock.IsRunning == isRunning);
|
||||
|
||||
protected override bool AllowFail => true;
|
||||
|
||||
@ -203,9 +286,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||
|
||||
public bool FailOverlayVisible => FailOverlay.State == Visibility.Visible;
|
||||
public bool FailOverlayVisible => FailOverlay.State.Value == Visibility.Visible;
|
||||
|
||||
public bool PauseOverlayVisible => PauseOverlay.State == Visibility.Visible;
|
||||
public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible;
|
||||
|
||||
public override void OnEntering(IScreen last)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
@ -7,44 +7,86 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestScenePlayerLoader : ManualInputManagerTestScene
|
||||
{
|
||||
private PlayerLoader loader;
|
||||
private OsuScreenStack stack;
|
||||
private TestPlayerLoader loader;
|
||||
private TestPlayerLoaderContainer container;
|
||||
private TestPlayer player;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
[Resolved]
|
||||
private AudioManager audioManager { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private SessionStatics sessionStatics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the input manager child to a new test player loader container instance.
|
||||
/// </summary>
|
||||
/// <param name="interactive">If the test player should behave like the production one.</param>
|
||||
/// <param name="beforeLoadAction">An action to run before player load but after bindable leases are returned.</param>
|
||||
/// <param name="afterLoadAction">An action to run after container load.</param>
|
||||
public void ResetPlayer(bool interactive, Action beforeLoadAction = null, Action afterLoadAction = null)
|
||||
{
|
||||
InputManager.Child = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
|
||||
Beatmap.Value = new TestWorkingBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), Clock);
|
||||
});
|
||||
audioManager.Volume.SetDefault();
|
||||
|
||||
InputManager.Clear();
|
||||
|
||||
beforeLoadAction?.Invoke();
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
|
||||
InputManager.Child = container = new TestPlayerLoaderContainer(
|
||||
loader = new TestPlayerLoader(() =>
|
||||
{
|
||||
afterLoadAction?.Invoke();
|
||||
return player = new TestPlayer(interactive, interactive);
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBlockLoadViaMouseMovement()
|
||||
{
|
||||
AddStep("load dummy beatmap", () => ResetPlayer(false));
|
||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
||||
AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20);
|
||||
AddAssert("loader still active", () => loader.IsCurrentScreen());
|
||||
AddUntilStep("loads after idle", () => !loader.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLoadContinuation()
|
||||
{
|
||||
Player player = null;
|
||||
SlowLoadPlayer slowPlayer = null;
|
||||
|
||||
AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => player = new TestPlayer(false, false))));
|
||||
AddStep("load dummy beatmap", () => ResetPlayer(false));
|
||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
||||
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen());
|
||||
AddStep("load slow dummy beatmap", () =>
|
||||
{
|
||||
stack.Push(loader = new PlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
|
||||
InputManager.Child = container = new TestPlayerLoaderContainer(
|
||||
loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
|
||||
|
||||
Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000);
|
||||
});
|
||||
|
||||
@ -54,16 +96,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestModReinstantiation()
|
||||
{
|
||||
TestPlayer player = null;
|
||||
TestMod gameMod = null;
|
||||
TestMod playerMod1 = null;
|
||||
TestMod playerMod2 = null;
|
||||
|
||||
AddStep("load player", () =>
|
||||
{
|
||||
Mods.Value = new[] { gameMod = new TestMod() };
|
||||
stack.Push(loader = new PlayerLoader(() => player = new TestPlayer()));
|
||||
});
|
||||
AddStep("load player", () => { ResetPlayer(true, () => Mods.Value = new[] { gameMod = new TestMod() }); });
|
||||
|
||||
AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen());
|
||||
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
|
||||
@ -86,6 +123,85 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("player mods applied", () => playerMod2.Applied);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMutedNotificationMasterVolume() => addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault);
|
||||
|
||||
[Test]
|
||||
public void TestMutedNotificationTrackVolume() => addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, null, () => audioManager.VolumeTrack.IsDefault);
|
||||
|
||||
[Test]
|
||||
public void TestMutedNotificationMuteButton() => addVolumeSteps("mute button", null, () => container.VolumeOverlay.IsMuted.Value = true, () => !container.VolumeOverlay.IsMuted.Value);
|
||||
|
||||
/// <remarks>
|
||||
/// Created for avoiding copy pasting code for the same steps.
|
||||
/// </remarks>
|
||||
/// <param name="volumeName">What part of the volume system is checked</param>
|
||||
/// <param name="beforeLoad">The action to be invoked to set the volume before loading</param>
|
||||
/// <param name="afterLoad">The action to be invoked to set the volume after loading</param>
|
||||
/// <param name="assert">The function to be invoked and checked</param>
|
||||
private void addVolumeSteps(string volumeName, Action beforeLoad, Action afterLoad, Func<bool> assert)
|
||||
{
|
||||
AddStep("reset notification lock", () => sessionStatics.GetBindable<bool>(Static.MutedAudioNotificationShownOnce).Value = false);
|
||||
|
||||
AddStep("load player", () => ResetPlayer(false, beforeLoad, afterLoad));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
|
||||
AddAssert("check for notification", () => container.NotificationOverlay.UnreadCount.Value == 1);
|
||||
AddStep("click notification", () =>
|
||||
{
|
||||
var scrollContainer = (OsuScrollContainer)container.NotificationOverlay.Children.Last();
|
||||
var flowContainer = scrollContainer.Children.OfType<FillFlowContainer<NotificationSection>>().First();
|
||||
var notification = flowContainer.First();
|
||||
|
||||
InputManager.MoveMouseTo(notification);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("check " + volumeName, assert);
|
||||
}
|
||||
|
||||
private class TestPlayerLoaderContainer : Container
|
||||
{
|
||||
[Cached]
|
||||
public readonly NotificationOverlay NotificationOverlay;
|
||||
|
||||
[Cached]
|
||||
public readonly VolumeOverlay VolumeOverlay;
|
||||
|
||||
public TestPlayerLoaderContainer(IScreen screen)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new OsuScreenStack(screen)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
NotificationOverlay = new NotificationOverlay
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
},
|
||||
VolumeOverlay = new VolumeOverlay
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class TestPlayerLoader : PlayerLoader
|
||||
{
|
||||
public new VisualSettings VisualSettings => base.VisualSettings;
|
||||
|
||||
public TestPlayerLoader(Func<Player> createPlayer)
|
||||
: base(createPlayer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMod : Mod, IApplicableToScoreProcessor
|
||||
{
|
||||
public override string Name => string.Empty;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Lists;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Play;
|
||||
@ -43,9 +42,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
}
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock clock)
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
var working = base.CreateWorkingBeatmap(beatmap, clock);
|
||||
var working = base.CreateWorkingBeatmap(beatmap);
|
||||
workingWeakReferences.Add(working);
|
||||
return working;
|
||||
}
|
||||
|
@ -26,12 +26,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)Player).ScoreProcessor.TotalScore.Value > 0);
|
||||
AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
|
||||
AddAssert("cannot fail", () => !((ScoreAccessibleReplayPlayer)Player).AllowFail);
|
||||
}
|
||||
|
||||
private class ScoreAccessibleReplayPlayer : ReplayPlayer
|
||||
{
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||
public new bool AllowFail => base.AllowFail;
|
||||
|
||||
protected override bool PauseOnFocusLost => false;
|
||||
|
||||
|
@ -0,0 +1,74 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Screens.Ranking.Pages;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneReplayDownloadButton : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ReplayDownloadButton)
|
||||
};
|
||||
|
||||
private TestReplayDownloadButton downloadButton;
|
||||
|
||||
public TestSceneReplayDownloadButton()
|
||||
{
|
||||
createButton(true);
|
||||
AddStep(@"downloading state", () => downloadButton.SetDownloadState(DownloadState.Downloading));
|
||||
AddStep(@"locally available state", () => downloadButton.SetDownloadState(DownloadState.LocallyAvailable));
|
||||
AddStep(@"not downloaded state", () => downloadButton.SetDownloadState(DownloadState.NotDownloaded));
|
||||
createButton(false);
|
||||
}
|
||||
|
||||
private void createButton(bool withReplay)
|
||||
{
|
||||
AddStep(withReplay ? @"create button with replay" : "create button without replay", () =>
|
||||
{
|
||||
Child = downloadButton = new TestReplayDownloadButton(getScoreInfo(withReplay))
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private ScoreInfo getScoreInfo(bool replayAvailable)
|
||||
{
|
||||
return new APILegacyScoreInfo
|
||||
{
|
||||
ID = 1,
|
||||
OnlineScoreID = 2553163309,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
Replay = replayAvailable,
|
||||
User = new User
|
||||
{
|
||||
Id = 39828,
|
||||
Username = @"WubWoofWolf",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class TestReplayDownloadButton : ReplayDownloadButton
|
||||
{
|
||||
public void SetDownloadState(DownloadState state) => State.Value = state;
|
||||
|
||||
public TestReplayDownloadButton(ScoreInfo score)
|
||||
: base(score)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
@ -20,6 +21,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
State = { Value = Visibility.Visible }
|
||||
});
|
||||
|
||||
Add(container = new ExampleContainer());
|
||||
|
@ -3,11 +3,16 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Ranking.Pages;
|
||||
@ -22,11 +27,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ScoreInfo),
|
||||
typeof(Results),
|
||||
typeof(ResultsPage),
|
||||
typeof(ScoreResultsPage),
|
||||
typeof(LocalLeaderboardPage)
|
||||
typeof(RetryButton),
|
||||
typeof(ReplayDownloadButton),
|
||||
typeof(LocalLeaderboardPage),
|
||||
typeof(TestPlayer)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -42,26 +49,82 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
|
||||
if (beatmapInfo != null)
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
|
||||
}
|
||||
|
||||
LoadScreen(new SoloResults(new ScoreInfo
|
||||
private TestSoloResults createResultsScreen() => new TestSoloResults(new ScoreInfo
|
||||
{
|
||||
TotalScore = 2845370,
|
||||
Accuracy = 0.98,
|
||||
MaxCombo = 123,
|
||||
Rank = ScoreRank.A,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics = new Dictionary<HitResult, int>
|
||||
{
|
||||
TotalScore = 2845370,
|
||||
Accuracy = 0.98,
|
||||
MaxCombo = 123,
|
||||
Rank = ScoreRank.A,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics = new Dictionary<HitResult, int>
|
||||
{ HitResult.Great, 50 },
|
||||
{ HitResult.Good, 20 },
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Miss, 1 }
|
||||
},
|
||||
User = new User
|
||||
{
|
||||
Username = "peppy",
|
||||
}
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void ResultsWithoutPlayer()
|
||||
{
|
||||
TestSoloResults screen = null;
|
||||
|
||||
AddStep("load results", () => Child = new OsuScreenStack(screen = createResultsScreen())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
});
|
||||
AddUntilStep("wait for loaded", () => screen.IsLoaded);
|
||||
AddAssert("retry overlay not present", () => screen.RetryOverlay == null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ResultsWithPlayer()
|
||||
{
|
||||
TestSoloResults screen = null;
|
||||
|
||||
AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen()));
|
||||
AddUntilStep("wait for loaded", () => screen.IsLoaded);
|
||||
AddAssert("retry overlay present", () => screen.RetryOverlay != null);
|
||||
}
|
||||
|
||||
private class TestResultsContainer : Container
|
||||
{
|
||||
[Cached(typeof(Player))]
|
||||
private readonly Player player = new TestPlayer();
|
||||
|
||||
public TestResultsContainer(IScreen screen)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = new OsuScreenStack(screen)
|
||||
{
|
||||
{ HitResult.Great, 50 },
|
||||
{ HitResult.Good, 20 },
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Miss, 1 }
|
||||
},
|
||||
User = new User
|
||||
{
|
||||
Username = "peppy",
|
||||
}
|
||||
}));
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSoloResults : SoloResults
|
||||
{
|
||||
public HotkeyRetryOverlay RetryOverlay;
|
||||
|
||||
public TestSoloResults(ScoreInfo score)
|
||||
: base(score)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
RetryOverlay = InternalChildren.OfType<HotkeyRetryOverlay>().SingleOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,10 +200,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestDrawableHitObject : DrawableHitObject<HitObject>
|
||||
@ -216,10 +212,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddInternal(new Box { Size = new Vector2(75) });
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,145 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneSkinReloadable : OsuTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestInitialLoad()
|
||||
{
|
||||
var secondarySource = new SecondarySource();
|
||||
SkinConsumer consumer = null;
|
||||
|
||||
AddStep("setup layout", () =>
|
||||
{
|
||||
Child = new SkinSourceContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new LocalSkinOverrideContainer(secondarySource)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
|
||||
AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOverride()
|
||||
{
|
||||
var secondarySource = new SecondarySource();
|
||||
|
||||
SkinConsumer consumer = null;
|
||||
Container target = null;
|
||||
|
||||
AddStep("setup layout", () =>
|
||||
{
|
||||
Child = new SkinSourceContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = target = new LocalSkinOverrideContainer(secondarySource)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)));
|
||||
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
|
||||
AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1);
|
||||
}
|
||||
|
||||
private class NamedBox : Container
|
||||
{
|
||||
public NamedBox(string name)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.Default.With(size: 40),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = name
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class SkinConsumer : SkinnableDrawable
|
||||
{
|
||||
public new Drawable Drawable => base.Drawable;
|
||||
public int SkinChangedCount { get; private set; }
|
||||
|
||||
public SkinConsumer(string name, Func<string, Drawable> defaultImplementation, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true)
|
||||
: base(name, defaultImplementation, allowFallback, restrictSize)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
SkinChangedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
private class BaseSourceBox : NamedBox
|
||||
{
|
||||
public BaseSourceBox()
|
||||
: base("Base Source")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class SecondarySourceBox : NamedBox
|
||||
{
|
||||
public SecondarySourceBox()
|
||||
: base("Secondary Source")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class SecondarySource : ISkin
|
||||
{
|
||||
public Drawable GetDrawableComponent(string componentName) => new SecondarySourceBox();
|
||||
|
||||
public Texture GetTexture(string componentName) => throw new NotImplementedException();
|
||||
|
||||
public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
|
||||
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private class SkinSourceContainer : Container, ISkin
|
||||
{
|
||||
public Drawable GetDrawableComponent(string componentName) => new BaseSourceBox();
|
||||
|
||||
public Texture GetTexture(string componentName) => throw new NotImplementedException();
|
||||
|
||||
public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
|
||||
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
350
osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
Normal file
350
osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
Normal file
@ -0,0 +1,350 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneSkinnableDrawable : OsuTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestConfineScaleDown()
|
||||
{
|
||||
FillFlowContainer<ExposedSkinnableDrawable> fill = null;
|
||||
|
||||
AddStep("setup layout larger source", () =>
|
||||
{
|
||||
Child = new SkinProvidingContainer(new SizedSource(50))
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = fill = new FillFlowContainer<ExposedSkinnableDrawable>
|
||||
{
|
||||
Size = new Vector2(30),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Spacing = new Vector2(10),
|
||||
Children = new[]
|
||||
{
|
||||
new ExposedSkinnableDrawable("default", _ => new DefaultBox(), _ => true),
|
||||
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true),
|
||||
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true, ConfineMode.ScaleToFit),
|
||||
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true, ConfineMode.NoScaling)
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("check sizes", () => fill.Children.Select(c => c.Drawable.DrawWidth).SequenceEqual(new float[] { 30, 30, 30, 50 }));
|
||||
AddStep("adjust scale", () => fill.Scale = new Vector2(2));
|
||||
AddAssert("check sizes unchanged by scale", () => fill.Children.Select(c => c.Drawable.DrawWidth).SequenceEqual(new float[] { 30, 30, 30, 50 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestConfineScaleUp()
|
||||
{
|
||||
FillFlowContainer<ExposedSkinnableDrawable> fill = null;
|
||||
|
||||
AddStep("setup layout larger source", () =>
|
||||
{
|
||||
Child = new SkinProvidingContainer(new SizedSource(30))
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = fill = new FillFlowContainer<ExposedSkinnableDrawable>
|
||||
{
|
||||
Size = new Vector2(50),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Spacing = new Vector2(10),
|
||||
Children = new[]
|
||||
{
|
||||
new ExposedSkinnableDrawable("default", _ => new DefaultBox(), _ => true),
|
||||
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true),
|
||||
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true, ConfineMode.ScaleToFit),
|
||||
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true, ConfineMode.NoScaling)
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("check sizes", () => fill.Children.Select(c => c.Drawable.DrawWidth).SequenceEqual(new float[] { 50, 30, 50, 30 }));
|
||||
AddStep("adjust scale", () => fill.Scale = new Vector2(2));
|
||||
AddAssert("check sizes unchanged by scale", () => fill.Children.Select(c => c.Drawable.DrawWidth).SequenceEqual(new float[] { 50, 30, 50, 30 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInitialLoad()
|
||||
{
|
||||
var secondarySource = new SecondarySource();
|
||||
SkinConsumer consumer = null;
|
||||
|
||||
AddStep("setup layout", () =>
|
||||
{
|
||||
Child = new SkinSourceContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new SkinProvidingContainer(secondarySource)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
|
||||
AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOverride()
|
||||
{
|
||||
var secondarySource = new SecondarySource();
|
||||
|
||||
SkinConsumer consumer = null;
|
||||
Container target = null;
|
||||
|
||||
AddStep("setup layout", () =>
|
||||
{
|
||||
Child = new SkinSourceContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = target = new SkinProvidingContainer(secondarySource)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)));
|
||||
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
|
||||
AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSwitchOff()
|
||||
{
|
||||
SkinConsumer consumer = null;
|
||||
SwitchableSkinProvidingContainer target = null;
|
||||
|
||||
AddStep("setup layout", () =>
|
||||
{
|
||||
Child = new SkinSourceContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = target = new SwitchableSkinProvidingContainer(new SecondarySource())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)));
|
||||
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
|
||||
AddStep("disable", () => target.Disable());
|
||||
AddAssert("consumer using base source", () => consumer.Drawable is BaseSourceBox);
|
||||
}
|
||||
|
||||
private class SwitchableSkinProvidingContainer : SkinProvidingContainer
|
||||
{
|
||||
private bool allow = true;
|
||||
|
||||
protected override bool AllowDrawableLookup(ISkinComponent component) => allow;
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
allow = false;
|
||||
TriggerSourceChanged();
|
||||
}
|
||||
|
||||
public SwitchableSkinProvidingContainer(ISkin skin)
|
||||
: base(skin)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class ExposedSkinnableDrawable : SkinnableDrawable
|
||||
{
|
||||
public new Drawable Drawable => base.Drawable;
|
||||
|
||||
public ExposedSkinnableDrawable(string name, Func<ISkinComponent, Drawable> defaultImplementation, Func<ISkinSource, bool> allowFallback = null,
|
||||
ConfineMode confineMode = ConfineMode.ScaleDownToFit)
|
||||
: base(new TestSkinComponent(name), defaultImplementation, allowFallback, confineMode)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultBox : DrawWidthBox
|
||||
{
|
||||
public DefaultBox()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
}
|
||||
|
||||
private class DrawWidthBox : Container
|
||||
{
|
||||
private readonly OsuSpriteText text;
|
||||
|
||||
public DrawWidthBox()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Gray,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
text.Text = DrawWidth.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
private class NamedBox : Container
|
||||
{
|
||||
public NamedBox(string name)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.Default.With(size: 40),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = name
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class SkinConsumer : SkinnableDrawable
|
||||
{
|
||||
public new Drawable Drawable => base.Drawable;
|
||||
public int SkinChangedCount { get; private set; }
|
||||
|
||||
public SkinConsumer(string name, Func<ISkinComponent, Drawable> defaultImplementation, Func<ISkinSource, bool> allowFallback = null)
|
||||
: base(new TestSkinComponent(name), defaultImplementation, allowFallback)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
SkinChangedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
private class BaseSourceBox : NamedBox
|
||||
{
|
||||
public BaseSourceBox()
|
||||
: base("Base Source")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class SecondarySourceBox : NamedBox
|
||||
{
|
||||
public SecondarySourceBox()
|
||||
: base("Secondary Source")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class SizedSource : ISkin
|
||||
{
|
||||
private readonly float size;
|
||||
|
||||
public SizedSource(float size)
|
||||
{
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent componentName) =>
|
||||
componentName.LookupName == "available"
|
||||
? new DrawWidthBox
|
||||
{
|
||||
Colour = Color4.Yellow,
|
||||
Size = new Vector2(size)
|
||||
}
|
||||
: null;
|
||||
|
||||
public Texture GetTexture(string componentName) => throw new NotImplementedException();
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private class SecondarySource : ISkin
|
||||
{
|
||||
public Drawable GetDrawableComponent(ISkinComponent componentName) => new SecondarySourceBox();
|
||||
|
||||
public Texture GetTexture(string componentName) => throw new NotImplementedException();
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[Cached(typeof(ISkinSource))]
|
||||
private class SkinSourceContainer : Container, ISkinSource
|
||||
{
|
||||
public Drawable GetDrawableComponent(ISkinComponent componentName) => new BaseSourceBox();
|
||||
|
||||
public Texture GetTexture(string componentName) => throw new NotImplementedException();
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
|
||||
public event Action SourceChanged
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSkinComponent : ISkinComponent
|
||||
{
|
||||
private readonly string name;
|
||||
|
||||
public TestSkinComponent(string name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public string ComponentGroup => string.Empty;
|
||||
|
||||
public string LookupName => name;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,88 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneSkipOverlay : OsuTestScene
|
||||
public class TestSceneSkipOverlay : ManualInputManagerTestScene
|
||||
{
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
private SkipOverlay skip;
|
||||
private int requestCount;
|
||||
|
||||
Add(new SkipOverlay(Clock.CurrentTime + 5000));
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
requestCount = 0;
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = new FramedOffsetClock(Clock)
|
||||
{
|
||||
Offset = -Clock.CurrentTime,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
skip = new SkipOverlay(6000)
|
||||
{
|
||||
RequestSeek = _ => requestCount++
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestFadeOnIdle()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(Vector2.Zero));
|
||||
AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
|
||||
AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
|
||||
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
|
||||
AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClickableAfterFade()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("wait for fade", () => skip.Children.First().Alpha == 0);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
checkRequestCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClickOnlyActuatesOnce()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
checkRequestCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoesntFadeOnMouseDown()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("button down", () => InputManager.PressButton(MouseButton.Left));
|
||||
AddUntilStep("wait for overlay disapper", () => !skip.IsAlive);
|
||||
AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0);
|
||||
AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
checkRequestCount(0);
|
||||
}
|
||||
|
||||
private void checkRequestCount(int expected) =>
|
||||
AddAssert($"request count is {expected}", () => requestCount == expected);
|
||||
}
|
||||
}
|
||||
|
@ -21,32 +21,38 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
private readonly Container<DrawableStoryboard> storyboardContainer;
|
||||
private DrawableStoryboard storyboard;
|
||||
|
||||
[Cached]
|
||||
private MusicController musicController = new MusicController();
|
||||
|
||||
public TestSceneStoryboard()
|
||||
{
|
||||
Clock = new FramedClock();
|
||||
|
||||
Add(new Container
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
musicController,
|
||||
new Container
|
||||
{
|
||||
new Box
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
storyboardContainer = new Container<DrawableStoryboard>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
storyboardContainer = new Container<DrawableStoryboard>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Add(new MusicController
|
||||
{
|
||||
Origin = Anchor.TopRight,
|
||||
Anchor = Anchor.TopRight,
|
||||
State = Visibility.Visible,
|
||||
new NowPlayingOverlay
|
||||
{
|
||||
Origin = Anchor.TopRight,
|
||||
Anchor = Anchor.TopRight,
|
||||
State = { Value = Visibility.Visible },
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("Restart", restart);
|
||||
|
69
osu.Game.Tests/Visual/Menus/IntroTestScene.cs
Normal file
69
osu.Game.Tests/Visual/Menus/IntroTestScene.cs
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public abstract class IntroTestScene : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(StartupScreen),
|
||||
typeof(IntroScreen),
|
||||
typeof(OsuScreen),
|
||||
typeof(IntroTestScene),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private OsuLogo logo;
|
||||
|
||||
protected IntroTestScene()
|
||||
{
|
||||
Drawable introStack = null;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = float.MaxValue,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
logo = new OsuLogo
|
||||
{
|
||||
Alpha = 0,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Depth = float.MinValue,
|
||||
Position = new Vector2(0.5f),
|
||||
}
|
||||
};
|
||||
|
||||
AddStep("restart sequence", () =>
|
||||
{
|
||||
logo.FinishTransforms();
|
||||
logo.IsTracking = false;
|
||||
|
||||
introStack?.Expire();
|
||||
|
||||
Add(introStack = new OsuScreenStack(CreateScreen())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract IScreen CreateScreen();
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Users;
|
||||
|
||||
@ -10,23 +9,18 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
public class TestSceneDisclaimer : ScreenTestScene
|
||||
{
|
||||
[Cached(typeof(IAPIProvider))]
|
||||
private readonly DummyAPIAccess api = new DummyAPIAccess();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(api);
|
||||
|
||||
AddStep("load disclaimer", () => LoadScreen(new Disclaimer()));
|
||||
|
||||
AddStep("toggle support", () =>
|
||||
{
|
||||
api.LocalUser.Value = new User
|
||||
API.LocalUser.Value = new User
|
||||
{
|
||||
Username = api.LocalUser.Value.Username,
|
||||
Id = api.LocalUser.Value.Id,
|
||||
IsSupporter = !api.LocalUser.Value.IsSupporter,
|
||||
Username = API.LocalUser.Value.Username,
|
||||
Id = API.LocalUser.Value.Id,
|
||||
IsSupporter = !API.LocalUser.Value.IsSupporter,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
15
osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs
Normal file
15
osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneIntroCircles : IntroTestScene
|
||||
{
|
||||
protected override IScreen CreateScreen() => new IntroCircles();
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneIntroSequence : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(OsuLogo),
|
||||
};
|
||||
|
||||
public TestSceneIntroSequence()
|
||||
{
|
||||
OsuLogo logo;
|
||||
|
||||
var rateAdjustClock = new StopwatchClock(true);
|
||||
var framedClock = new FramedClock(rateAdjustClock);
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
Add(new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = framedClock,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
logo = new OsuLogo
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AddStep(@"Restart", logo.PlayIntro);
|
||||
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v);
|
||||
}
|
||||
}
|
||||
}
|
15
osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs
Normal file
15
osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneIntroTriangles : IntroTestScene
|
||||
{
|
||||
protected override IScreen CreateScreen() => new IntroTriangles();
|
||||
}
|
||||
}
|
@ -33,23 +33,15 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
[Test]
|
||||
public void TestInstantLoad()
|
||||
{
|
||||
bool logoVisible = false;
|
||||
// visual only, very impossible to test this using asserts.
|
||||
|
||||
AddStep("begin loading", () =>
|
||||
AddStep("load immediately", () =>
|
||||
{
|
||||
loader = new TestLoader();
|
||||
loader.AllowLoad.Set();
|
||||
|
||||
LoadScreen(loader);
|
||||
});
|
||||
|
||||
AddUntilStep("loaded", () =>
|
||||
{
|
||||
logoVisible = loader.Logo?.Alpha > 0;
|
||||
return loader.Logo != null && loader.ScreenLoaded;
|
||||
});
|
||||
|
||||
AddAssert("logo was not visible", () => !logoVisible);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -58,7 +50,7 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
AddStep("begin loading", () => LoadScreen(loader = new TestLoader()));
|
||||
AddUntilStep("wait for logo visible", () => loader.Logo?.Alpha > 0);
|
||||
AddStep("finish loading", () => loader.AllowLoad.Set());
|
||||
AddAssert("loaded", () => loader.Logo != null && loader.ScreenLoaded);
|
||||
AddUntilStep("loaded", () => loader.Logo != null && loader.ScreenLoaded);
|
||||
AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
|
||||
}
|
||||
|
||||
|
244
osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs
Normal file
244
osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs
Normal file
@ -0,0 +1,244 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
using IntroSequence = osu.Game.Configuration.IntroSequence;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
public class TestSceneScreenNavigation : ManualInputManagerTestScene
|
||||
{
|
||||
private const float click_padding = 25;
|
||||
|
||||
private GameHost host;
|
||||
private TestOsuGame game;
|
||||
|
||||
private Vector2 backButtonPosition => game.ToScreenSpace(new Vector2(click_padding, game.LayoutRectangle.Bottom - click_padding));
|
||||
|
||||
private Vector2 optionsButtonPosition => game.ToScreenSpace(new Vector2(click_padding, click_padding));
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
this.host = host;
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
};
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("Create new game instance", () =>
|
||||
{
|
||||
if (game != null)
|
||||
{
|
||||
Remove(game);
|
||||
game.Dispose();
|
||||
}
|
||||
|
||||
game = new TestOsuGame(LocalStorage, API);
|
||||
game.SetHost(host);
|
||||
|
||||
// todo: this can be removed once we can run audio trakcs without a device present
|
||||
// see https://github.com/ppy/osu/issues/1302
|
||||
game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
|
||||
|
||||
Add(game);
|
||||
});
|
||||
AddUntilStep("Wait for load", () => game.IsLoaded);
|
||||
AddUntilStep("Wait for intro", () => game.ScreenStack.CurrentScreen is IntroScreen);
|
||||
confirmAtMainMenu();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitSongSelectWithEscape()
|
||||
{
|
||||
TestSongSelect songSelect = null;
|
||||
|
||||
pushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
||||
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
||||
pushEscape();
|
||||
AddAssert("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
|
||||
exitViaEscapeAndConfirm();
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestSongContinuesAfterExitPlayer(bool withUserPause)
|
||||
{
|
||||
Player player = null;
|
||||
|
||||
WorkingBeatmap beatmap() => game.Beatmap.Value;
|
||||
Track track() => beatmap().Track;
|
||||
|
||||
pushAndConfirm(() => new TestSongSelect());
|
||||
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Wait());
|
||||
|
||||
AddUntilStep("wait for selected", () => !game.Beatmap.IsDefault);
|
||||
|
||||
if (withUserPause)
|
||||
AddStep("pause", () => game.Dependencies.Get<MusicController>().Stop());
|
||||
|
||||
AddStep("press enter", () => pressAndRelease(Key.Enter));
|
||||
|
||||
AddUntilStep("wait for player", () => (player = game.ScreenStack.CurrentScreen as Player) != null);
|
||||
AddUntilStep("wait for fail", () => player.HasFailed);
|
||||
|
||||
AddUntilStep("wait for track stop", () => !track().IsRunning);
|
||||
AddAssert("Ensure time before preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime);
|
||||
|
||||
pushEscape();
|
||||
|
||||
AddUntilStep("wait for track playing", () => track().IsRunning);
|
||||
AddAssert("Ensure time wasn't reset to preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitSongSelectWithClick()
|
||||
{
|
||||
TestSongSelect songSelect = null;
|
||||
|
||||
pushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
||||
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
||||
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
|
||||
|
||||
// BackButton handles hover using its child button, so this checks whether or not any of BackButton's children are hovered.
|
||||
AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == game.BackButton));
|
||||
|
||||
AddStep("Click back button", () => InputManager.Click(MouseButton.Left));
|
||||
AddUntilStep("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
|
||||
exitViaBackButtonAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitMultiWithEscape()
|
||||
{
|
||||
pushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
exitViaEscapeAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitMultiWithBackButton()
|
||||
{
|
||||
pushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
exitViaBackButtonAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOpenOptionsAndExitWithEscape()
|
||||
{
|
||||
AddUntilStep("Wait for options to load", () => game.Settings.IsLoaded);
|
||||
AddStep("Enter menu", () => pressAndRelease(Key.Enter));
|
||||
AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition));
|
||||
AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left));
|
||||
AddAssert("Options overlay was opened", () => game.Settings.State.Value == Visibility.Visible);
|
||||
AddStep("Hide options overlay using escape", () => pressAndRelease(Key.Escape));
|
||||
AddAssert("Options overlay was closed", () => game.Settings.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
private void pushAndConfirm(Func<Screen> newScreen)
|
||||
{
|
||||
Screen screen = null;
|
||||
AddStep("Push new screen", () => game.ScreenStack.Push(screen = newScreen()));
|
||||
AddUntilStep("Wait for new screen", () => game.ScreenStack.CurrentScreen == screen && screen.IsLoaded);
|
||||
}
|
||||
|
||||
private void pushEscape() =>
|
||||
AddStep("Press escape", () => pressAndRelease(Key.Escape));
|
||||
|
||||
private void exitViaEscapeAndConfirm()
|
||||
{
|
||||
pushEscape();
|
||||
confirmAtMainMenu();
|
||||
}
|
||||
|
||||
private void exitViaBackButtonAndConfirm()
|
||||
{
|
||||
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
|
||||
AddStep("Click back button", () => InputManager.Click(MouseButton.Left));
|
||||
confirmAtMainMenu();
|
||||
}
|
||||
|
||||
private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => game.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded);
|
||||
|
||||
private void pressAndRelease(Key key)
|
||||
{
|
||||
InputManager.PressKey(key);
|
||||
InputManager.ReleaseKey(key);
|
||||
}
|
||||
|
||||
private class TestOsuGame : OsuGame
|
||||
{
|
||||
public new ScreenStack ScreenStack => base.ScreenStack;
|
||||
|
||||
public new BackButton BackButton => base.BackButton;
|
||||
|
||||
public new SettingsPanel Settings => base.Settings;
|
||||
|
||||
public new OsuConfigManager LocalConfig => base.LocalConfig;
|
||||
|
||||
public new Bindable<WorkingBeatmap> Beatmap => base.Beatmap;
|
||||
|
||||
protected override Loader CreateLoader() => new TestLoader();
|
||||
|
||||
public TestOsuGame(Storage storage, IAPIProvider api)
|
||||
{
|
||||
Storage = storage;
|
||||
API = api;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
API.Login("Rhythm Champion", "osu!");
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSongSelect : PlaySongSelect
|
||||
{
|
||||
public ModSelectOverlay ModSelectOverlay => ModSelect;
|
||||
}
|
||||
|
||||
private class TestLoader : Loader
|
||||
{
|
||||
protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler();
|
||||
|
||||
private class TestShaderPrecompiler : ShaderPrecompiler
|
||||
{
|
||||
protected override bool AllLoaded => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,13 +17,13 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
typeof(ToolbarButton),
|
||||
typeof(ToolbarRulesetSelector),
|
||||
typeof(ToolbarRulesetButton),
|
||||
typeof(ToolbarRulesetTabButton),
|
||||
typeof(ToolbarNotificationButton),
|
||||
};
|
||||
|
||||
public TestSceneToolbar()
|
||||
{
|
||||
var toolbar = new Toolbar { State = Visibility.Visible };
|
||||
var toolbar = new Toolbar { State = { Value = Visibility.Visible } };
|
||||
ToolbarNotificationButton notificationButton = null;
|
||||
|
||||
AddStep("create toolbar", () =>
|
||||
|
@ -0,0 +1,53 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Audio;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
[Cached(typeof(IPreviewTrackOwner))]
|
||||
public class TestSceneMatchBeatmapPanel : MultiplayerTestScene, IPreviewTrackOwner
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(MatchBeatmapPanel)
|
||||
};
|
||||
|
||||
[Resolved]
|
||||
private PreviewTrackManager previewTrackManager { get; set; }
|
||||
|
||||
public TestSceneMatchBeatmapPanel()
|
||||
{
|
||||
Add(new MatchBeatmapPanel
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1763072 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2101557 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1973466 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2109801 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1922035 } });
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
AddStep("Select random beatmap", () =>
|
||||
{
|
||||
Room.CurrentItem.Value = Room.Playlist[RNG.Next(Room.Playlist.Count)];
|
||||
previewTrackManager.StopAnyPlaying(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
typeof(Info),
|
||||
typeof(HeaderButton),
|
||||
typeof(ReadyButton),
|
||||
typeof(ViewBeatmapButton)
|
||||
typeof(MatchBeatmapPanel)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -14,6 +14,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchLeaderboard : MultiplayerTestScene
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public TestSceneMatchLeaderboard()
|
||||
{
|
||||
Room.RoomID.Value = 3;
|
||||
@ -27,11 +29,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
});
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(IAPIProvider api)
|
||||
{
|
||||
var req = new GetRoomScoresRequest();
|
||||
req.Success += v => { };
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
@ -37,7 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
settings = new TestRoomSettings
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
State = Visibility.Visible
|
||||
State = { Value = Visibility.Visible }
|
||||
};
|
||||
|
||||
Child = settings;
|
||||
@ -57,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("set name", () => Room.Name.Value = "Room name");
|
||||
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
|
||||
|
||||
AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = new DummyWorkingBeatmap().BeatmapInfo }));
|
||||
AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo }));
|
||||
AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
|
||||
|
||||
AddStep("clear name", () => Room.Name.Value = "");
|
||||
|
@ -12,6 +12,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[TestFixture]
|
||||
public class TestSceneMultiScreen : ScreenTestScene
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(Screens.Multi.Multiplayer),
|
||||
|
@ -4,9 +4,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.AccountCreation;
|
||||
using osu.Game.Users;
|
||||
@ -25,17 +25,16 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(AccountCreationScreen),
|
||||
};
|
||||
|
||||
[Cached(typeof(IAPIProvider))]
|
||||
private DummyAPIAccess api = new DummyAPIAccess();
|
||||
private readonly Container userPanelArea;
|
||||
|
||||
private Bindable<User> localUser;
|
||||
|
||||
public TestSceneAccountCreationOverlay()
|
||||
{
|
||||
Container userPanelArea;
|
||||
AccountCreationOverlay accountCreation;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
api,
|
||||
accountCreation = new AccountCreationOverlay(),
|
||||
userPanelArea = new Container
|
||||
{
|
||||
@ -46,11 +45,18 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
};
|
||||
|
||||
api.Logout();
|
||||
api.LocalUser.BindValueChanged(user => { userPanelArea.Child = new UserPanel(user.NewValue) { Width = 200 }; }, true);
|
||||
AddStep("show", () => accountCreation.Show());
|
||||
}
|
||||
|
||||
AddStep("show", () => accountCreation.State = Visibility.Visible);
|
||||
AddStep("logout", () => api.Logout());
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
API.Logout();
|
||||
|
||||
localUser = API.LocalUser.GetBoundCopy();
|
||||
localUser.BindValueChanged(user => { userPanelArea.Child = new UserPanel(user.NewValue) { Width = 200 }; }, true);
|
||||
|
||||
AddStep("logout", API.Logout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
95
osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs
Normal file
95
osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneBeatmapAvailability : OsuTestScene
|
||||
{
|
||||
private readonly BeatmapAvailability container;
|
||||
|
||||
public TestSceneBeatmapAvailability()
|
||||
{
|
||||
Add(container = new BeatmapAvailability());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUndownloadableWithLink()
|
||||
{
|
||||
AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = @"https://osu.ppy.sh",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
visiblityAssert(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUndownloadableNoLink()
|
||||
{
|
||||
AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
visiblityAssert(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPartsRemovedWithLink()
|
||||
{
|
||||
AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = false,
|
||||
ExternalLink = @"https://osu.ppy.sh",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
visiblityAssert(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNormal()
|
||||
{
|
||||
AddStep("set normal beatmapset", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
visiblityAssert(false);
|
||||
}
|
||||
|
||||
private void visiblityAssert(bool shown)
|
||||
{
|
||||
AddAssert($"is container {(shown ? "visible" : "hidden")}", () => container.Alpha == (shown ? 1 : 0));
|
||||
}
|
||||
}
|
||||
}
|
102
osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
Normal file
102
osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Rulesets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneBeatmapRulesetSelector : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(BeatmapRulesetSelector),
|
||||
typeof(BeatmapRulesetTabItem),
|
||||
};
|
||||
|
||||
private readonly TestRulesetSelector selector;
|
||||
|
||||
public TestSceneBeatmapRulesetSelector()
|
||||
{
|
||||
Add(selector = new TestRulesetSelector());
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestMultipleRulesetsBeatmapSet()
|
||||
{
|
||||
var enabledRulesets = rulesets.AvailableRulesets.Skip(1).Take(2);
|
||||
|
||||
AddStep("load multiple rulesets beatmapset", () =>
|
||||
{
|
||||
selector.BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
Beatmaps = enabledRulesets.Select(r => new BeatmapInfo { Ruleset = r }).ToList()
|
||||
};
|
||||
});
|
||||
|
||||
var tabItems = selector.TabContainer.TabItems;
|
||||
AddAssert("other rulesets disabled", () => tabItems.Except(tabItems.Where(t => enabledRulesets.Any(r => r.Equals(t.Value)))).All(t => !t.Enabled.Value));
|
||||
AddAssert("left-most ruleset selected", () => tabItems.First(t => t.Enabled.Value).Active.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSingleRulesetBeatmapSet()
|
||||
{
|
||||
var enabledRuleset = rulesets.AvailableRulesets.Last();
|
||||
|
||||
AddStep("load single ruleset beatmapset", () =>
|
||||
{
|
||||
selector.BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = enabledRuleset
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("single ruleset selected", () => selector.SelectedTab.Value.Equals(enabledRuleset));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyBeatmapSet()
|
||||
{
|
||||
AddStep("load empty beatmapset", () => selector.BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
Beatmaps = new List<BeatmapInfo>()
|
||||
});
|
||||
|
||||
AddAssert("no ruleset selected", () => selector.SelectedTab == null);
|
||||
AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNullBeatmapSet()
|
||||
{
|
||||
AddStep("load null beatmapset", () => selector.BeatmapSet = null);
|
||||
|
||||
AddAssert("no ruleset selected", () => selector.SelectedTab == null);
|
||||
AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value));
|
||||
}
|
||||
|
||||
private class TestRulesetSelector : BeatmapRulesetSelector
|
||||
{
|
||||
public new TabItem<RulesetInfo> SelectedTab => base.SelectedTab;
|
||||
|
||||
public new TabFillFlowContainer TabContainer => base.TabContainer;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[TestFixture]
|
||||
public class TestSceneBeatmapSetOverlay : OsuTestScene
|
||||
{
|
||||
private readonly BeatmapSetOverlay overlay;
|
||||
private readonly TestBeatmapSetOverlay overlay;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@ -32,375 +32,304 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(BasicStats),
|
||||
typeof(BeatmapPicker),
|
||||
typeof(Details),
|
||||
typeof(DownloadButton),
|
||||
typeof(HeaderDownloadButton),
|
||||
typeof(FavouriteButton),
|
||||
typeof(Header),
|
||||
typeof(HeaderButton),
|
||||
typeof(Info),
|
||||
typeof(PreviewButton),
|
||||
typeof(SuccessRate),
|
||||
typeof(BeatmapAvailability),
|
||||
typeof(BeatmapRulesetSelector),
|
||||
typeof(BeatmapRulesetTabItem),
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public TestSceneBeatmapSetOverlay()
|
||||
{
|
||||
Add(overlay = new BeatmapSetOverlay());
|
||||
Add(overlay = new TestBeatmapSetOverlay());
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestLoading()
|
||||
{
|
||||
var mania = rulesets.GetRuleset(3);
|
||||
var taiko = rulesets.GetRuleset(1);
|
||||
|
||||
AddStep(@"show loading", () => overlay.ShowBeatmapSet(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnline()
|
||||
{
|
||||
AddStep(@"show online", () => overlay.FetchAndShowBeatmapSet(55));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLocalBeatmaps()
|
||||
{
|
||||
AddStep(@"show first", () =>
|
||||
{
|
||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1235,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"Lachryma <Re:Queen’M>",
|
||||
Artist = @"Kaneko Chiharu",
|
||||
Source = @"SOUND VOLTEX III GRAVITY WARS",
|
||||
Tags = @"sdvx grace the 5th kac original song contest konami bemani",
|
||||
Title = @"an awesome beatmap",
|
||||
Artist = @"naru narusegawa",
|
||||
Source = @"hinata sou",
|
||||
Tags = @"test tag tag more tag",
|
||||
Author = new User
|
||||
{
|
||||
Username = @"Fresh Chicken",
|
||||
Id = 3984370,
|
||||
Username = @"BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Preview = @"https://b.ppy.sh/preview/415886.mp3",
|
||||
PlayCount = 681380,
|
||||
FavouriteCount = 356,
|
||||
Submitted = new DateTime(2016, 2, 10),
|
||||
Ranked = new DateTime(2016, 6, 19),
|
||||
Status = BeatmapSetOnlineStatus.Ranked,
|
||||
BPM = 236,
|
||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
Submitted = DateTime.Now,
|
||||
Ranked = DateTime.Now,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = @"https://assets.ppy.sh/beatmaps/415886/covers/cover.jpg?1465651778",
|
||||
},
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 1.36,
|
||||
Version = @"BASIC",
|
||||
Ruleset = mania,
|
||||
StarDifficulty = 9.99,
|
||||
Version = @"TEST",
|
||||
Length = 456000,
|
||||
Ruleset = rulesets.GetRuleset(3),
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 4,
|
||||
DrainRate = 6.5f,
|
||||
OverallDifficulty = 6.5f,
|
||||
ApproachRate = 5,
|
||||
CircleSize = 1,
|
||||
DrainRate = 2.3f,
|
||||
OverallDifficulty = 4.5f,
|
||||
ApproachRate = 6,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 115000,
|
||||
CircleCount = 265,
|
||||
SliderCount = 71,
|
||||
PlayCount = 47906,
|
||||
PassCount = 19899,
|
||||
CircleCount = 111,
|
||||
SliderCount = 12,
|
||||
PlayCount = 222,
|
||||
PassCount = 21,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 2.22,
|
||||
Version = @"NOVICE",
|
||||
Ruleset = mania,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 4,
|
||||
DrainRate = 7,
|
||||
OverallDifficulty = 7,
|
||||
ApproachRate = 5,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 118000,
|
||||
CircleCount = 592,
|
||||
SliderCount = 62,
|
||||
PlayCount = 162021,
|
||||
PassCount = 72116,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 3.49,
|
||||
Version = @"ADVANCED",
|
||||
Ruleset = mania,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 4,
|
||||
DrainRate = 7.5f,
|
||||
OverallDifficulty = 7.5f,
|
||||
ApproachRate = 5,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 118000,
|
||||
CircleCount = 1042,
|
||||
SliderCount = 79,
|
||||
PlayCount = 225178,
|
||||
PassCount = 73001,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 4.24,
|
||||
Version = @"EXHAUST",
|
||||
Ruleset = mania,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 4,
|
||||
DrainRate = 8,
|
||||
OverallDifficulty = 8,
|
||||
ApproachRate = 5,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 118000,
|
||||
CircleCount = 1352,
|
||||
SliderCount = 69,
|
||||
PlayCount = 131545,
|
||||
PassCount = 42703,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 5.26,
|
||||
Version = @"GRAVITY",
|
||||
Ruleset = mania,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 4,
|
||||
DrainRate = 8.5f,
|
||||
OverallDifficulty = 8.5f,
|
||||
ApproachRate = 5,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 118000,
|
||||
CircleCount = 1730,
|
||||
SliderCount = 115,
|
||||
PlayCount = 117673,
|
||||
PassCount = 24241,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
AddStep(@"show second", () =>
|
||||
downloadAssert(true);
|
||||
|
||||
AddStep("show many difficulties", () => overlay.ShowBeatmapSet(createManyDifficultiesBeatmapSet()));
|
||||
downloadAssert(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAvailability()
|
||||
{
|
||||
AddStep(@"show undownloadable", () =>
|
||||
{
|
||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1234,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"undownloadable beatmap",
|
||||
Artist = @"no one",
|
||||
Source = @"some source",
|
||||
Tags = @"another test tag tag more test tags",
|
||||
Author = new User
|
||||
{
|
||||
Username = @"BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = "https://osu.ppy.sh",
|
||||
},
|
||||
Preview = @"https://b.ppy.sh/preview/1234.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
Submitted = DateTime.Now,
|
||||
Ranked = DateTime.Now,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Language = new BeatmapSetOnlineLanguage { Id = 3, Name = "English" },
|
||||
Genre = new BeatmapSetOnlineGenre { Id = 4, Name = "Rock" },
|
||||
},
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 5.67,
|
||||
Version = @"ANOTHER TEST",
|
||||
Length = 123000,
|
||||
Ruleset = rulesets.GetRuleset(1),
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 9,
|
||||
DrainRate = 8,
|
||||
OverallDifficulty = 7,
|
||||
ApproachRate = 6,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
CircleCount = 123,
|
||||
SliderCount = 45,
|
||||
PlayCount = 567,
|
||||
PassCount = 89,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
downloadAssert(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleRulesets()
|
||||
{
|
||||
AddStep("show multiple rulesets beatmap", () =>
|
||||
{
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
|
||||
foreach (var ruleset in rulesets.AvailableRulesets.Skip(1))
|
||||
{
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
Version = ruleset.Name,
|
||||
Ruleset = ruleset,
|
||||
BaseDifficulty = new BeatmapDifficulty(),
|
||||
OnlineInfo = new BeatmapOnlineInfo(),
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"Soumatou Labyrinth",
|
||||
Artist = @"Yunomi with Momobako&miko",
|
||||
Tags = @"mmbk.com yuzu__rinrin charlotte",
|
||||
Title = @"multiple rulesets beatmap",
|
||||
Artist = @"none",
|
||||
Author = new User
|
||||
{
|
||||
Username = @"komasy",
|
||||
Id = 1980256,
|
||||
},
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
}
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Preview = @"https://b.ppy.sh/preview/625493.mp3",
|
||||
PlayCount = 22996,
|
||||
FavouriteCount = 58,
|
||||
Submitted = new DateTime(2016, 6, 11),
|
||||
Ranked = new DateTime(2016, 7, 12),
|
||||
Status = BeatmapSetOnlineStatus.Pending,
|
||||
BPM = 160,
|
||||
HasVideo = false,
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = @"https://assets.ppy.sh/beatmaps/625493/covers/cover.jpg?1499167472",
|
||||
},
|
||||
},
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 1.40,
|
||||
Version = @"yzrin's Kantan",
|
||||
Ruleset = taiko,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 2,
|
||||
DrainRate = 7,
|
||||
OverallDifficulty = 3,
|
||||
ApproachRate = 10,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 193000,
|
||||
CircleCount = 262,
|
||||
SliderCount = 0,
|
||||
PlayCount = 3952,
|
||||
PassCount = 1373,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 2.23,
|
||||
Version = @"Futsuu",
|
||||
Ruleset = taiko,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 2,
|
||||
DrainRate = 6,
|
||||
OverallDifficulty = 4,
|
||||
ApproachRate = 10,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 193000,
|
||||
CircleCount = 464,
|
||||
SliderCount = 0,
|
||||
PlayCount = 4833,
|
||||
PassCount = 920,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 3.19,
|
||||
Version = @"Muzukashii",
|
||||
Ruleset = taiko,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 2,
|
||||
DrainRate = 6,
|
||||
OverallDifficulty = 5,
|
||||
ApproachRate = 10,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 193000,
|
||||
CircleCount = 712,
|
||||
SliderCount = 0,
|
||||
PlayCount = 4405,
|
||||
PassCount = 854,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 3.97,
|
||||
Version = @"Charlotte's Oni",
|
||||
Ruleset = taiko,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 5,
|
||||
DrainRate = 6,
|
||||
OverallDifficulty = 5.5f,
|
||||
ApproachRate = 10,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 193000,
|
||||
CircleCount = 943,
|
||||
SliderCount = 0,
|
||||
PlayCount = 3950,
|
||||
PassCount = 693,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 5.08,
|
||||
Version = @"Labyrinth Oni",
|
||||
Ruleset = taiko,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 5,
|
||||
DrainRate = 5,
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 10,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 193000,
|
||||
CircleCount = 1068,
|
||||
SliderCount = 0,
|
||||
PlayCount = 5856,
|
||||
PassCount = 1207,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11),
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
},
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
|
||||
Beatmaps = beatmaps
|
||||
});
|
||||
});
|
||||
|
||||
AddAssert("shown beatmaps of current ruleset", () => overlay.Header.Picker.Difficulties.All(b => b.Beatmap.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value)));
|
||||
AddAssert("left-most beatmap selected", () => overlay.Header.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHide()
|
||||
{
|
||||
AddStep(@"hide", overlay.Hide);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestShowWithNoReload()
|
||||
{
|
||||
AddStep(@"show without reload", overlay.Show);
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createManyDifficultiesBeatmapSet()
|
||||
{
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
|
||||
for (int i = 1; i < 41; i++)
|
||||
{
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = i * 10,
|
||||
Version = $"Test #{i}",
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 2 + i * 0.1,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo(),
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 123,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"many difficulties beatmap",
|
||||
Artist = @"none",
|
||||
Author = new User
|
||||
{
|
||||
Username = @"BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Preview = @"https://b.ppy.sh/preview/123.mp3",
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
|
||||
Beatmaps = beatmaps,
|
||||
};
|
||||
}
|
||||
|
||||
private void downloadAssert(bool shown)
|
||||
{
|
||||
AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.DownloadButtonsVisible == shown);
|
||||
}
|
||||
|
||||
private class TestBeatmapSetOverlay : BeatmapSetOverlay
|
||||
{
|
||||
public new Header Header => base.Header;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT 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.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneBeatmapSetOverlayDetails : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(Details)
|
||||
};
|
||||
|
||||
private RatingsExposingDetails details;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Child = details = new RatingsExposingDetails
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestMetrics()
|
||||
{
|
||||
var firstSet = createSet();
|
||||
var secondSet = createSet();
|
||||
|
||||
AddStep("set first set", () => details.BeatmapSet = firstSet);
|
||||
AddAssert("ratings set", () => details.Ratings.Metrics == firstSet.Metrics);
|
||||
|
||||
AddStep("set second set", () => details.BeatmapSet = secondSet);
|
||||
AddAssert("ratings set", () => details.Ratings.Metrics == secondSet.Metrics);
|
||||
|
||||
BeatmapSetInfo createSet() => new BeatmapSetInfo
|
||||
{
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray() },
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class RatingsExposingDetails : Details
|
||||
{
|
||||
public new UserRatings Ratings => base.Ratings;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneBeatmapSetOverlaySuccessRate : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(Details)
|
||||
};
|
||||
|
||||
private GraphExposingSuccessRate successRate;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(275, 220),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Gray,
|
||||
},
|
||||
successRate = new GraphExposingSuccessRate
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(275, 220),
|
||||
Padding = new MarginPadding(20)
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestMetrics()
|
||||
{
|
||||
var firstBeatmap = createBeatmap();
|
||||
var secondBeatmap = createBeatmap();
|
||||
|
||||
AddStep("set first set", () => successRate.Beatmap = firstBeatmap);
|
||||
AddAssert("ratings set", () => successRate.Graph.Metrics == firstBeatmap.Metrics);
|
||||
|
||||
AddStep("set second set", () => successRate.Beatmap = secondBeatmap);
|
||||
AddAssert("ratings set", () => successRate.Graph.Metrics == secondBeatmap.Metrics);
|
||||
|
||||
BeatmapInfo createBeatmap() => new BeatmapInfo
|
||||
{
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class GraphExposingSuccessRate : SuccessRate
|
||||
{
|
||||
public new FailRetryGraph Graph => base.Graph;
|
||||
}
|
||||
}
|
||||
}
|
@ -24,8 +24,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(ChangelogListing),
|
||||
typeof(ChangelogSingleBuild),
|
||||
typeof(ChangelogBuild),
|
||||
typeof(Comments),
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@ -42,7 +45,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
Version = "2018.712.0",
|
||||
DisplayVersion = "2018.712.0",
|
||||
UpdateStream = new APIUpdateStream { Name = "lazer" },
|
||||
UpdateStream = new APIUpdateStream { Name = OsuGameBase.CLIENT_STREAM_NAME },
|
||||
ChangelogEntries = new List<APIChangelogEntry>
|
||||
{
|
||||
new APIChangelogEntry
|
||||
@ -65,6 +68,34 @@ namespace osu.Game.Tests.Visual.Online
|
||||
changelog.ShowListing();
|
||||
changelog.Show();
|
||||
});
|
||||
|
||||
AddStep(@"Ensure HTML string unescaping", () =>
|
||||
{
|
||||
changelog.ShowBuild(new APIChangelogBuild
|
||||
{
|
||||
Version = "2019.920.0",
|
||||
DisplayVersion = "2019.920.0",
|
||||
UpdateStream = new APIUpdateStream
|
||||
{
|
||||
Name = "Test",
|
||||
DisplayName = "Test"
|
||||
},
|
||||
ChangelogEntries = new List<APIChangelogEntry>
|
||||
{
|
||||
new APIChangelogEntry
|
||||
{
|
||||
Category = "Testing HTML strings unescaping",
|
||||
Title = "Ensuring HTML strings are being unescaped",
|
||||
MessageHtml = """"This text should appear triple-quoted""" >_<",
|
||||
GithubUser = new APIChangelogUser
|
||||
{
|
||||
DisplayName = "Dummy",
|
||||
OsuUsername = "Dummy",
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
});
|
||||
|
||||
channelTabControl.OnRequestLeave += channel => channelTabControl.RemoveChannel(channel);
|
||||
channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue.ToString();
|
||||
channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue;
|
||||
|
||||
AddStep("Add random private channel", addRandomPrivateChannel);
|
||||
AddAssert("There is only one channels", () => channelTabControl.Items.Count() == 2);
|
||||
|
@ -1,45 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Chat;
|
||||
using osu.Game.Overlays.Chat.Tabs;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
[Description("Testing chat api and overlay")]
|
||||
public class TestSceneChatDisplay : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ChatOverlay),
|
||||
typeof(ChatLine),
|
||||
typeof(DrawableChannel),
|
||||
typeof(ChannelSelectorTabItem),
|
||||
typeof(ChannelTabControl),
|
||||
typeof(ChannelTabItem),
|
||||
typeof(PrivateChannelTabItem),
|
||||
typeof(TabCloseButton)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly ChannelManager channelManager = new ChannelManager();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
channelManager,
|
||||
new ChatOverlay { State = Visibility.Visible }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
108
osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs
Normal file
108
osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Overlays.Chat;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneChatLineTruncation : OsuTestScene
|
||||
{
|
||||
private readonly TestChatLineContainer textContainer;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ChatLine),
|
||||
typeof(Message),
|
||||
typeof(LinkFlowContainer),
|
||||
typeof(MessageFormatter)
|
||||
};
|
||||
|
||||
public TestSceneChatLineTruncation()
|
||||
{
|
||||
Add(textContainer = new TestChatLineContainer
|
||||
{
|
||||
Padding = new MarginPadding { Left = 20, Right = 20 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
testFormatting();
|
||||
}
|
||||
|
||||
private void clear() => AddStep("clear messages", textContainer.Clear);
|
||||
|
||||
private void addMessageWithChecks(string text, bool isAction = false, bool isImportant = false, string username = null)
|
||||
{
|
||||
int index = textContainer.Count + 1;
|
||||
var newLine = new ChatLine(new DummyMessage(text, isAction, isImportant, index, username));
|
||||
textContainer.Add(newLine);
|
||||
}
|
||||
|
||||
private void testFormatting()
|
||||
{
|
||||
for (int a = 0; a < 25; a++)
|
||||
addMessageWithChecks($"Wide {a} character username.", username: new string('w', a));
|
||||
addMessageWithChecks("Short name with spaces.", username: "sho rt name");
|
||||
addMessageWithChecks("Long name with spaces.", username: "long name with s p a c e s");
|
||||
}
|
||||
|
||||
private class DummyMessage : Message
|
||||
{
|
||||
private static long messageCounter;
|
||||
|
||||
internal static readonly User TEST_SENDER_BACKGROUND = new User
|
||||
{
|
||||
Username = @"i-am-important",
|
||||
Id = 42,
|
||||
Colour = "#250cc9",
|
||||
};
|
||||
|
||||
internal static readonly User TEST_SENDER = new User
|
||||
{
|
||||
Username = @"Somebody",
|
||||
Id = 1,
|
||||
};
|
||||
|
||||
public new DateTimeOffset Timestamp = DateTimeOffset.Now;
|
||||
|
||||
public DummyMessage(string text, bool isAction = false, bool isImportant = false, int number = 0, string username = null)
|
||||
: base(messageCounter++)
|
||||
{
|
||||
Content = text;
|
||||
IsAction = isAction;
|
||||
Sender = new User
|
||||
{
|
||||
Username = username ?? $"user {number}",
|
||||
Id = number,
|
||||
Colour = isImportant ? "#250cc9" : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class TestChatLineContainer : FillFlowContainer<ChatLine>
|
||||
{
|
||||
protected override int Compare(Drawable x, Drawable y)
|
||||
{
|
||||
var xC = (ChatLine)x;
|
||||
var yC = (ChatLine)y;
|
||||
|
||||
return xC.Message.CompareTo(yC.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -127,6 +127,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
addMessageWithChecks("is now playing [https://osu.ppy.sh/b/252238 IMAGE -MATERIAL- <Version 0>]", 1, true, expectedActions: LinkAction.OpenBeatmap);
|
||||
addMessageWithChecks("Let's (try)[https://osu.ppy.sh/home] [https://osu.ppy.sh/b/252238 multiple links] https://osu.ppy.sh/home", 3,
|
||||
expectedActions: new[] { LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External });
|
||||
addMessageWithChecks("[https://osu.ppy.sh/home New link format with escaped [and \\[ paired] braces]", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("[Markdown link format with escaped [and \\[ paired] braces](https://osu.ppy.sh/home)", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("(Old link format with escaped (and \\( paired) parentheses)[https://osu.ppy.sh/home] and [[also a rogue wiki link]]", 2, expectedActions: new[] { LinkAction.External, LinkAction.External });
|
||||
// note that there's 0 links here (they get removed if a channel is not found)
|
||||
addMessageWithChecks("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).");
|
||||
addMessageWithChecks("I am important!", 0, false, true);
|
||||
|
157
osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
Normal file
157
osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
Normal file
@ -0,0 +1,157 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Chat;
|
||||
using osu.Game.Overlays.Chat.Selection;
|
||||
using osu.Game.Overlays.Chat.Tabs;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneChatOverlay : ManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ChatLine),
|
||||
typeof(DrawableChannel),
|
||||
typeof(ChannelSelectorTabItem),
|
||||
typeof(ChannelTabControl),
|
||||
typeof(ChannelTabItem),
|
||||
typeof(PrivateChannelTabItem),
|
||||
typeof(TabCloseButton)
|
||||
};
|
||||
|
||||
private TestChatOverlay chatOverlay;
|
||||
private ChannelManager channelManager;
|
||||
|
||||
private readonly Channel channel1 = new Channel(new User()) { Name = "test really long username" };
|
||||
private readonly Channel channel2 = new Channel(new User()) { Name = "test2" };
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
ChannelManagerContainer container;
|
||||
|
||||
Child = container = new ChannelManagerContainer(new List<Channel> { channel1, channel2 })
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
|
||||
chatOverlay = container.ChatOverlay;
|
||||
channelManager = container.ChannelManager;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHideOverlay()
|
||||
{
|
||||
AddAssert("Chat overlay is visible", () => chatOverlay.State.Value == Visibility.Visible);
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
|
||||
AddStep("Close chat overlay", () => chatOverlay.Hide());
|
||||
|
||||
AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden);
|
||||
AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelectingChannelClosesSelector()
|
||||
{
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
|
||||
AddStep("Join channel 1", () => channelManager.JoinChannel(channel1));
|
||||
AddStep("Switch to channel 1", () => clickDrawable(chatOverlay.TabMap[channel1]));
|
||||
|
||||
AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1);
|
||||
AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCloseChannelWhileSelectorClosed()
|
||||
{
|
||||
AddStep("Join channel 1", () => channelManager.JoinChannel(channel1));
|
||||
AddStep("Join channel 2", () => channelManager.JoinChannel(channel2));
|
||||
|
||||
AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2]));
|
||||
AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child));
|
||||
|
||||
AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1);
|
||||
|
||||
AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child));
|
||||
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
}
|
||||
|
||||
private void clickDrawable(Drawable d)
|
||||
{
|
||||
InputManager.MoveMouseTo(d);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
}
|
||||
|
||||
private class ChannelManagerContainer : Container
|
||||
{
|
||||
public TestChatOverlay ChatOverlay { get; private set; }
|
||||
|
||||
[Cached]
|
||||
public ChannelManager ChannelManager { get; } = new ChannelManager();
|
||||
|
||||
private readonly List<Channel> channels;
|
||||
|
||||
public ChannelManagerContainer(List<Channel> channels)
|
||||
{
|
||||
this.channels = channels;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
((BindableList<Channel>)ChannelManager.AvailableChannels).AddRange(channels);
|
||||
|
||||
Child = ChatOverlay = new TestChatOverlay { RelativeSizeAxes = Axes.Both, };
|
||||
ChatOverlay.Show();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestChatOverlay : ChatOverlay
|
||||
{
|
||||
public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value;
|
||||
|
||||
public new ChannelSelectionOverlay ChannelSelectionOverlay => base.ChannelSelectionOverlay;
|
||||
|
||||
protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl();
|
||||
|
||||
public IReadOnlyDictionary<Channel, TabItem<Channel>> TabMap => ((TestTabControl)ChannelTabControl).TabMap;
|
||||
}
|
||||
|
||||
private class TestTabControl : ChannelTabControl
|
||||
{
|
||||
protected override TabItem<Channel> CreateTabItem(Channel value) => new TestChannelTabItem(value);
|
||||
|
||||
public new IReadOnlyDictionary<Channel, TabItem<Channel>> TabMap => base.TabMap;
|
||||
}
|
||||
|
||||
private class TestChannelTabItem : PrivateChannelTabItem
|
||||
{
|
||||
public TestChannelTabItem(Channel channel)
|
||||
: base(channel)
|
||||
{
|
||||
}
|
||||
|
||||
public new ClickableContainer CloseButton => base.CloseButton;
|
||||
}
|
||||
}
|
||||
}
|
59
osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs
Normal file
59
osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Comments;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneCommentsContainer : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CommentsContainer),
|
||||
typeof(CommentsHeader),
|
||||
typeof(DrawableComment),
|
||||
typeof(HeaderButton),
|
||||
typeof(SortTabControl),
|
||||
typeof(ShowChildrenButton),
|
||||
typeof(DeletedChildrenPlaceholder),
|
||||
typeof(VotePill)
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public TestSceneCommentsContainer()
|
||||
{
|
||||
BasicScrollContainer scrollFlow;
|
||||
|
||||
Add(scrollFlow = new BasicScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
});
|
||||
|
||||
AddStep("Big Black comments", () =>
|
||||
{
|
||||
scrollFlow.Clear();
|
||||
scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 41823));
|
||||
});
|
||||
|
||||
AddStep("Airman comments", () =>
|
||||
{
|
||||
scrollFlow.Clear();
|
||||
scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 24313));
|
||||
});
|
||||
|
||||
AddStep("lazer build comments", () =>
|
||||
{
|
||||
scrollFlow.Clear();
|
||||
scrollFlow.Add(new CommentsContainer(CommentableType.Build, 4772));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
39
osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs
Normal file
39
osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Overlays.Comments;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneCommentsHeader : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CommentsHeader),
|
||||
typeof(HeaderButton),
|
||||
typeof(SortTabControl),
|
||||
};
|
||||
|
||||
private readonly Bindable<CommentsSortCriteria> sort = new Bindable<CommentsSortCriteria>();
|
||||
private readonly BindableBool showDeleted = new BindableBool();
|
||||
|
||||
public TestSceneCommentsHeader()
|
||||
{
|
||||
Add(new CommentsHeader
|
||||
{
|
||||
Sort = { BindTarget = sort },
|
||||
ShowDeleted = { BindTarget = showDeleted }
|
||||
});
|
||||
|
||||
AddStep("Trigger ShowDeleted", () => showDeleted.Value = !showDeleted.Value);
|
||||
AddStep("Select old", () => sort.Value = CommentsSortCriteria.Old);
|
||||
AddStep("Select new", () => sort.Value = CommentsSortCriteria.New);
|
||||
AddStep("Select top", () => sort.Value = CommentsSortCriteria.Top);
|
||||
}
|
||||
}
|
||||
}
|
158
osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
Normal file
158
osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
Normal file
@ -0,0 +1,158 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT 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.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneDirectDownloadButton : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(PanelDownloadButton)
|
||||
};
|
||||
|
||||
private TestDownloadButton downloadButton;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestDownloadableBeatmap()
|
||||
{
|
||||
createButton(true);
|
||||
assertEnabled(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUndownloadableBeatmap()
|
||||
{
|
||||
createButton(false);
|
||||
assertEnabled(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDownloadState()
|
||||
{
|
||||
AddUntilStep("ensure manager loaded", () => beatmaps != null);
|
||||
ensureSoleilyRemoved();
|
||||
createButtonWithBeatmap(createSoleily());
|
||||
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
|
||||
AddStep("import soleily", () => beatmaps.Import(new[] { TestResources.GetTestBeatmapForImport() }));
|
||||
AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526));
|
||||
createButtonWithBeatmap(createSoleily());
|
||||
AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
|
||||
ensureSoleilyRemoved();
|
||||
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
|
||||
}
|
||||
|
||||
private void ensureSoleilyRemoved()
|
||||
{
|
||||
AddStep("remove soleily", () =>
|
||||
{
|
||||
var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == 241526);
|
||||
|
||||
if (beatmap != null) beatmaps.Delete(beatmap);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertEnabled(bool enabled)
|
||||
{
|
||||
AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => downloadButton.DownloadEnabled == enabled);
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createSoleily()
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
ID = 1,
|
||||
OnlineBeatmapSetID = 241526,
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = false,
|
||||
ExternalLink = string.Empty,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private void createButtonWithBeatmap(BeatmapSetInfo beatmap)
|
||||
{
|
||||
AddStep("create button", () =>
|
||||
{
|
||||
Child = downloadButton = new TestDownloadButton(beatmap)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(75, 50),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void createButton(bool downloadable)
|
||||
{
|
||||
AddStep("create button", () =>
|
||||
{
|
||||
Child = downloadButton = new TestDownloadButton(downloadable ? getDownloadableBeatmapSet() : getUndownloadableBeatmapSet())
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(75, 50),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private BeatmapSetInfo getDownloadableBeatmapSet()
|
||||
{
|
||||
var normal = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
|
||||
normal.OnlineInfo.HasVideo = true;
|
||||
normal.OnlineInfo.HasStoryboard = true;
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
private BeatmapSetInfo getUndownloadableBeatmapSet()
|
||||
{
|
||||
var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
|
||||
beatmap.Metadata.Artist = "test";
|
||||
beatmap.Metadata.Title = "undownloadable";
|
||||
beatmap.Metadata.AuthorString = "test";
|
||||
|
||||
beatmap.OnlineInfo.HasVideo = true;
|
||||
beatmap.OnlineInfo.HasStoryboard = true;
|
||||
|
||||
beatmap.OnlineInfo.Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = "http://osu.ppy.sh",
|
||||
};
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
private class TestDownloadButton : PanelDownloadButton
|
||||
{
|
||||
public new bool DownloadEnabled => base.DownloadEnabled;
|
||||
|
||||
public DownloadState DownloadState => State.Value;
|
||||
|
||||
public TestDownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
|
||||
: base(beatmapSet, noVideo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,8 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -14,7 +12,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
public class TestSceneDirectOverlay : OsuTestScene
|
||||
{
|
||||
private DirectOverlay direct;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
@ -25,18 +24,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
AddStep(@"toggle", direct.ToggleVisibility);
|
||||
AddStep(@"result counts", () => direct.ResultAmounts = new DirectOverlay.ResultCounts(1, 4, 13));
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
AddStep(@"trigger disabled", () => Ruleset.Disabled = !Ruleset.Disabled);
|
||||
}
|
||||
|
||||
private void newBeatmaps()
|
||||
{
|
||||
var ruleset = rulesets.GetRuleset(0);
|
||||
|
||||
direct.BeatmapSets = new[]
|
||||
{
|
||||
new BeatmapSetInfo
|
||||
@ -65,7 +57,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 5.35f,
|
||||
Metadata = new BeatmapMetadata(),
|
||||
},
|
||||
@ -97,7 +89,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 5.81f,
|
||||
Metadata = new BeatmapMetadata(),
|
||||
},
|
||||
@ -129,23 +121,23 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 0.9f,
|
||||
Metadata = new BeatmapMetadata(),
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 1.1f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 2.02f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 3.49f,
|
||||
},
|
||||
},
|
||||
@ -176,43 +168,43 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 1.26f,
|
||||
Metadata = new BeatmapMetadata(),
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 2.01f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 2.87f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 3.76f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 3.93f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 4.37f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 5.13f,
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 5.42f,
|
||||
},
|
||||
},
|
||||
|
@ -6,9 +6,10 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
@ -22,25 +23,115 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(IconPill)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private BeatmapSetInfo getUndownloadableBeatmapSet() => new BeatmapSetInfo
|
||||
{
|
||||
var beatmap = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, null);
|
||||
beatmap.BeatmapSetInfo.OnlineInfo.HasVideo = true;
|
||||
beatmap.BeatmapSetInfo.OnlineInfo.HasStoryboard = true;
|
||||
|
||||
Child = new FillFlowContainer
|
||||
OnlineBeatmapSetID = 123,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Padding = new MarginPadding(20),
|
||||
Spacing = new Vector2(0, 20),
|
||||
Children = new Drawable[]
|
||||
Title = "undownloadable beatmap",
|
||||
Artist = "test",
|
||||
Source = "more tests",
|
||||
Author = new User
|
||||
{
|
||||
new DirectGridPanel(beatmap.BeatmapSetInfo),
|
||||
new DirectListPanel(beatmap.BeatmapSetInfo)
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
},
|
||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = Ruleset.Value,
|
||||
Version = "Test",
|
||||
StarDifficulty = 6.42,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private BeatmapSetInfo getManyDifficultiesBeatmapSet(RulesetStore rulesets)
|
||||
{
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
Ruleset = rulesets.GetRuleset(i % 4),
|
||||
StarDifficulty = 2 + i % 4 * 2,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "many difficulties beatmap",
|
||||
Artist = "test",
|
||||
Author = new User
|
||||
{
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
}
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Beatmaps = beatmaps,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
var normal = CreateWorkingBeatmap(Ruleset.Value).BeatmapSetInfo;
|
||||
normal.OnlineInfo.HasVideo = true;
|
||||
normal.OnlineInfo.HasStoryboard = true;
|
||||
|
||||
var undownloadable = getUndownloadableBeatmapSet();
|
||||
var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
|
||||
|
||||
Child = new BasicScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Full,
|
||||
Padding = new MarginPadding(20),
|
||||
Spacing = new Vector2(5, 20),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DirectGridPanel(normal),
|
||||
new DirectGridPanel(undownloadable),
|
||||
new DirectGridPanel(manyDifficulties),
|
||||
new DirectListPanel(normal),
|
||||
new DirectListPanel(undownloadable),
|
||||
new DirectListPanel(manyDifficulties),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
54
osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs
Normal file
54
osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneFavouriteButton : OsuTestScene
|
||||
{
|
||||
private FavouriteButton favourite;
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("create button", () => Child = favourite = new FavouriteButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Size = new Vector2(50),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLoggedOutIn()
|
||||
{
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
||||
AddStep("log out", () => API.Logout());
|
||||
checkEnabled(false);
|
||||
AddStep("log in", () => API.Login("test", "test"));
|
||||
checkEnabled(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapChange()
|
||||
{
|
||||
AddStep("log in", () => API.Login("test", "test"));
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
||||
checkEnabled(true);
|
||||
AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo());
|
||||
checkEnabled(false);
|
||||
}
|
||||
|
||||
private void checkEnabled(bool expected)
|
||||
{
|
||||
AddAssert("is " + (expected ? "enabled" : "disabled"), () => favourite.Enabled.Value == expected);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,24 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
int fireCount = 0;
|
||||
|
||||
Add(overlay = new TestFullscreenOverlay());
|
||||
AddStep(@"toggle", overlay.ToggleVisibility);
|
||||
|
||||
overlay.State.ValueChanged += _ => fireCount++;
|
||||
|
||||
AddStep(@"show", overlay.Show);
|
||||
|
||||
AddAssert("fire count 1", () => fireCount == 1);
|
||||
|
||||
AddStep(@"show again", overlay.Show);
|
||||
|
||||
// this logic is specific to FullscreenOverlay
|
||||
AddAssert("fire count 2", () => fireCount == 2);
|
||||
|
||||
AddStep(@"hide", overlay.Hide);
|
||||
|
||||
AddAssert("fire count 3", () => fireCount == 3);
|
||||
}
|
||||
|
||||
private class TestFullscreenOverlay : FullscreenOverlay
|
||||
|
@ -5,9 +5,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Profile.Sections;
|
||||
using osu.Game.Overlays.Profile.Sections.Historical;
|
||||
using osu.Game.Users;
|
||||
@ -17,14 +17,15 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[TestFixture]
|
||||
public class TestSceneHistoricalSection : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes =>
|
||||
new[]
|
||||
{
|
||||
typeof(HistoricalSection),
|
||||
typeof(PaginatedMostPlayedBeatmapContainer),
|
||||
typeof(DrawableMostPlayedRow),
|
||||
typeof(DrawableProfileRow)
|
||||
};
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(HistoricalSection),
|
||||
typeof(PaginatedMostPlayedBeatmapContainer),
|
||||
typeof(DrawableMostPlayedBeatmap),
|
||||
typeof(DrawableProfileRow)
|
||||
};
|
||||
|
||||
public TestSceneHistoricalSection()
|
||||
{
|
||||
@ -36,7 +37,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Colour = OsuColour.Gray(0.2f)
|
||||
});
|
||||
|
||||
Add(new ScrollContainer
|
||||
Add(new OsuScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = section = new HistoricalSection(),
|
||||
|
246
osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs
Normal file
246
osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs
Normal file
@ -0,0 +1,246 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Overlays.Profile.Sections.Kudosu;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneKudosuHistory : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableKudosuHistoryItem),
|
||||
};
|
||||
|
||||
private readonly Box background;
|
||||
|
||||
public TestSceneKudosuHistory()
|
||||
{
|
||||
FillFlowContainer<DrawableKudosuHistoryItem> content;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
content = new FillFlowContainer<DrawableKudosuHistoryItem>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.7f,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
}
|
||||
});
|
||||
|
||||
items.ForEach(t => content.Add(new DrawableKudosuHistoryItem(t)));
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
background.Colour = colours.GreySeafoam;
|
||||
}
|
||||
|
||||
private readonly IEnumerable<APIKudosuHistory> items = new[]
|
||||
{
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 10,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2011, 11, 11)),
|
||||
Source = KudosuSource.DenyKudosu,
|
||||
Action = KudosuAction.Reset,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 1",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username1",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 5,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2012, 10, 11)),
|
||||
Source = KudosuSource.Forum,
|
||||
Action = KudosuAction.Give,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 2",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username2",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 8,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2013, 9, 11)),
|
||||
Source = KudosuSource.Forum,
|
||||
Action = KudosuAction.Reset,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 3",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username3",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 7,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2014, 8, 11)),
|
||||
Source = KudosuSource.Forum,
|
||||
Action = KudosuAction.Revoke,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 4",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username4",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 100,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2015, 7, 11)),
|
||||
Source = KudosuSource.Vote,
|
||||
Action = KudosuAction.Give,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 5",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username5",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 20,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)),
|
||||
Source = KudosuSource.Vote,
|
||||
Action = KudosuAction.Reset,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 6",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username6",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 11,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)),
|
||||
Source = KudosuSource.AllowKudosu,
|
||||
Action = KudosuAction.Give,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 7",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username7",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 24,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2014, 6, 11)),
|
||||
Source = KudosuSource.Delete,
|
||||
Action = KudosuAction.Reset,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 8",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username8",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 12,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)),
|
||||
Source = KudosuSource.Restore,
|
||||
Action = KudosuAction.Give,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 9",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username9",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 2,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2012, 6, 11)),
|
||||
Source = KudosuSource.Recalculate,
|
||||
Action = KudosuAction.Give,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 10",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username10",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
},
|
||||
new APIKudosuHistory
|
||||
{
|
||||
Amount = 32,
|
||||
CreatedAt = new DateTimeOffset(new DateTime(2019, 8, 11)),
|
||||
Source = KudosuSource.Recalculate,
|
||||
Action = KudosuAction.Reset,
|
||||
Post = new APIKudosuHistory.ModdingPost
|
||||
{
|
||||
Title = @"Random post 11",
|
||||
Url = @"https://osu.ppy.sh/b/1234",
|
||||
},
|
||||
Giver = new APIKudosuHistory.KudosuGiver
|
||||
{
|
||||
Username = @"Username11",
|
||||
Url = @"https://osu.ppy.sh/u/1234"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneLeaderboardScopeSelector : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(LeaderboardScopeSelector),
|
||||
};
|
||||
|
||||
public TestSceneLeaderboardScopeSelector()
|
||||
{
|
||||
Bindable<BeatmapLeaderboardScope> scope = new Bindable<BeatmapLeaderboardScope>();
|
||||
|
||||
Add(new LeaderboardScopeSelector
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Current = { BindTarget = scope }
|
||||
});
|
||||
|
||||
AddStep(@"Select global", () => scope.Value = BeatmapLeaderboardScope.Global);
|
||||
AddStep(@"Select country", () => scope.Value = BeatmapLeaderboardScope.Country);
|
||||
AddStep(@"Select friend", () => scope.Value = BeatmapLeaderboardScope.Friend);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user