1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-03 03:20:16 +08:00

Compare commits

...

99 Commits

317 changed files with 6663 additions and 15739 deletions
@@ -5,8 +5,9 @@ on:
types: [opened]
permissions:
issues: write # to read the labels of any linked issue(s), and to put the found labels if any on the PR
# not granting any `pull_requests` permissions because in github's modeling pull requests are a subset of issues. it's confusing.
issues: write
pull-requests: write
contents: read
jobs:
copy-labels:
+1 -1
View File
@@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.209.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.303.0" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.
@@ -5,7 +5,7 @@ using BenchmarkDotNet.Attributes;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Tests.NonVisual.Filtering;
namespace osu.Game.Benchmarks
{
@@ -42,7 +42,7 @@ namespace osu.Game.Benchmarks
Status = BeatmapOnlineStatus.Loved
};
private CarouselBeatmap carouselBeatmap = null!;
private FilterMatchingTest.CarouselBeatmap carouselBeatmap = null!;
private FilterCriteria criteria1 = null!;
private FilterCriteria criteria2 = null!;
private FilterCriteria criteria3 = null!;
@@ -55,7 +55,7 @@ namespace osu.Game.Benchmarks
var beatmap = getExampleBeatmap();
beatmap.OnlineID = 20201010;
beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 };
carouselBeatmap = new CarouselBeatmap(beatmap);
carouselBeatmap = new FilterMatchingTest.CarouselBeatmap(beatmap);
criteria1 = new FilterCriteria();
criteria2 = new FilterCriteria
{
@@ -3,10 +3,13 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Tests.Beatmaps;
@@ -30,6 +33,16 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
PathType.LINEAR,
new Vector2(100, 0),
new Vector2(100, 100)
),
createPathSegment(
PathType.PERFECT_CURVE,
new Vector2(100.009f, -50.0009f),
new Vector2(200.0089f, -100)
),
createPathSegment(
PathType.PERFECT_CURVE,
new Vector2(25, -50),
new Vector2(100, 75)
)
};
@@ -48,9 +61,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
[TestCase(0, 250)]
[TestCase(0, 200)]
[TestCase(1, 120)]
[TestCase(1, 80)]
public void TestSliderReversal(int pathIndex, double length)
[TestCase(1, 120, false, false)]
[TestCase(1, 80, false, false)]
[TestCase(2, 250)]
[TestCase(2, 190)]
[TestCase(3, 250)]
[TestCase(3, 190)]
public void TestSliderReversal(int pathIndex, double length, bool assertEqualDistances = true, bool assertSliderReduction = true)
{
var controlPoints = paths[pathIndex];
@@ -90,6 +107,215 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
InputManager.ReleaseKey(Key.LControl);
});
if (pathIndex == 2)
{
AddRepeatStep("Reverse slider again", () =>
{
InputManager.PressKey(Key.LControl);
InputManager.Key(Key.G);
InputManager.ReleaseKey(Key.LControl);
}, 2);
}
if (assertEqualDistances)
{
AddAssert("Middle control point has the same distance from start to end", () =>
{
var pathControlPoints = selectedSlider.Path.ControlPoints;
float middleToStart = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[0].Position);
float middleToEnd = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^1].Position);
return Precision.AlmostEquals(middleToStart, middleToEnd, 1f);
});
}
AddAssert("Middle control point is not at start or end", () =>
Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldStartPos) > 1 &&
Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldEndPos) > 1
);
AddAssert("Slider has correct length", () =>
Precision.AlmostEquals(selectedSlider.Path.Distance, oldDistance));
AddAssert("Slider has correct start position", () =>
Vector2.Distance(selectedSlider.Position, oldEndPos) < 1);
AddAssert("Slider has correct end position", () =>
Vector2.Distance(selectedSlider.EndPosition, oldStartPos) < 1);
AddAssert("Control points have correct types", () =>
{
var newControlPointTypes = selectedSlider.Path.ControlPoints.Select(p => p.Type).ToArray();
return oldControlPointTypes.Take(newControlPointTypes.Length).SequenceEqual(newControlPointTypes);
});
if (assertSliderReduction)
{
AddStep("Move to marker", () =>
{
var marker = this.ChildrenOfType<SliderEndDragMarker>().Single();
var markerPos = (marker.ScreenSpaceDrawQuad.TopRight + marker.ScreenSpaceDrawQuad.BottomRight) / 2;
// sometimes the cursor may miss the marker's hitbox so we
// add a little offset here to be sure it lands in a clickable position.
var position = new Vector2(markerPos.X + 2f, markerPos.Y);
InputManager.MoveMouseTo(position);
});
AddStep("Click", () => InputManager.PressButton(MouseButton.Left));
AddStep("Reduce slider", () =>
{
var middleControlPoint = this.ChildrenOfType<PathControlPointPiece<Slider>>().ToArray()[^2];
InputManager.MoveMouseTo(middleControlPoint);
});
AddStep("Release click", () => InputManager.ReleaseButton(MouseButton.Left));
AddStep("Save half slider info", () =>
{
oldStartPos = selectedSlider.Position;
oldEndPos = selectedSlider.EndPosition;
oldDistance = selectedSlider.Path.Distance;
});
AddStep("Reverse slider", () =>
{
InputManager.PressKey(Key.LControl);
InputManager.Key(Key.G);
InputManager.ReleaseKey(Key.LControl);
});
AddAssert("Middle control point has the same distance from start to end", () =>
{
var pathControlPoints = selectedSlider.Path.ControlPoints;
float middleToStart = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[0].Position);
float middleToEnd = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^1].Position);
return Precision.AlmostEquals(middleToStart, middleToEnd, 1f);
});
AddAssert("Middle control point is not at start or end", () =>
Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldStartPos) > 1 &&
Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldEndPos) > 1
);
AddAssert("Slider has correct length", () =>
Precision.AlmostEquals(selectedSlider.Path.Distance, oldDistance));
AddAssert("Slider has correct start position", () =>
Vector2.Distance(selectedSlider.Position, oldEndPos) < 1);
AddAssert("Slider has correct end position", () =>
Vector2.Distance(selectedSlider.EndPosition, oldStartPos) < 1);
AddAssert("Control points have correct types", () =>
{
var newControlPointTypes = selectedSlider.Path.ControlPoints.Select(p => p.Type).ToArray();
return oldControlPointTypes.Take(newControlPointTypes.Length).SequenceEqual(newControlPointTypes);
});
}
}
[Test]
public void TestSegmentedSliderReversal()
{
PathControlPoint[] segmentedSliderPath =
[
new PathControlPoint
{
Position = new Vector2(0, 0),
Type = PathType.PERFECT_CURVE
},
new PathControlPoint
{
Position = new Vector2(100, 150),
},
new PathControlPoint
{
Position = new Vector2(75, -50),
Type = PathType.PERFECT_CURVE
},
new PathControlPoint
{
Position = new Vector2(225, -75),
},
new PathControlPoint
{
Position = new Vector2(350, 50),
Type = PathType.PERFECT_CURVE
},
new PathControlPoint
{
Position = new Vector2(500, -75),
},
new PathControlPoint
{
Position = new Vector2(350, -120),
},
];
Vector2 oldStartPos = default;
Vector2 oldEndPos = default;
double oldDistance = default;
var oldControlPointTypes = segmentedSliderPath.Select(p => p.Type);
AddStep("Add slider", () =>
{
var slider = new Slider
{
Position = new Vector2(0, 200),
Path = new SliderPath(segmentedSliderPath)
{
ExpectedDistance = { Value = 1314 }
}
};
EditorBeatmap.Add(slider);
oldStartPos = slider.Position;
oldEndPos = slider.EndPosition;
oldDistance = slider.Path.Distance;
});
AddStep("Select slider", () =>
{
var slider = (Slider)EditorBeatmap.HitObjects[0];
EditorBeatmap.SelectedHitObjects.Add(slider);
});
AddRepeatStep("Reverse slider", () =>
{
InputManager.PressKey(Key.LControl);
InputManager.Key(Key.G);
InputManager.ReleaseKey(Key.LControl);
}, 3);
AddAssert("First arc's control is not at the slider's middle", () =>
Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, selectedSlider.Path.PositionAt(0.5)) > 1
);
AddAssert("Last arc's control is not at the slider's middle", () =>
Vector2.Distance(selectedSlider.Path.ControlPoints[1].Position, selectedSlider.Path.PositionAt(0.5)) > 1
);
AddAssert("First arc centered middle control point", () =>
{
var pathControlPoints = selectedSlider.Path.ControlPoints;
float middleToStart = Vector2.Distance(pathControlPoints[1].Position, pathControlPoints[0].Position);
float middleToEnd = Vector2.Distance(pathControlPoints[1].Position, pathControlPoints[2].Position);
return Precision.AlmostEquals(middleToStart, middleToEnd, 1f);
});
AddAssert("Last arc centered middle control point", () =>
{
var pathControlPoints = selectedSlider.Path.ControlPoints;
float middleToStart = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^3].Position);
float middleToEnd = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^1].Position);
return Precision.AlmostEquals(middleToStart, middleToEnd, 1f);
});
AddAssert("Slider has correct length", () =>
Precision.AlmostEquals(selectedSlider.Path.Distance, oldDistance));
@@ -0,0 +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.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests.Mods
{
public partial class TestSceneOsuModEasy : OsuModTestScene
{
protected override bool AllowFail => true;
[Test]
public void TestMultipleApplication()
{
bool reapplied = false;
CreateModTest(new ModTestData
{
Mods = [new OsuModEasy { Retries = { Value = 1 } }],
Autoplay = false,
CreateBeatmap = () =>
{
// do stuff to speed up fails
var b = new TestBeatmap(new OsuRuleset().RulesetInfo)
{
Difficulty = { DrainRate = 10 }
};
foreach (var ho in b.HitObjects)
ho.StartTime /= 4;
return b;
},
PassCondition = () =>
{
if (((ModEasyTestPlayer)Player).FailuresSuppressed > 0 && !reapplied)
{
try
{
foreach (var mod in Player.GameplayState.Mods.OfType<IApplicableToDifficulty>())
mod.ApplyToDifficulty(new BeatmapDifficulty());
foreach (var mod in Player.GameplayState.Mods.OfType<IApplicableToPlayer>())
mod.ApplyToPlayer(Player);
}
catch
{
// don't care if this fails. in fact a failure here is probably better than the alternative.
}
finally
{
reapplied = true;
}
}
return Player.GameplayState.HasFailed && ((ModEasyTestPlayer)Player).FailuresSuppressed <= 1;
}
});
}
protected override TestPlayer CreateModPlayer(Ruleset ruleset) => new ModEasyTestPlayer(CurrentTestData, AllowFail);
private partial class ModEasyTestPlayer : ModTestPlayer
{
public int FailuresSuppressed { get; private set; }
public ModEasyTestPlayer(ModTestData data, bool allowFail)
: base(data, allowFail)
{
}
protected override bool CheckModsAllowFailure()
{
bool failureAllowed = GameplayState.Mods.OfType<IApplicableFailOverride>().All(m => m.PerformFail());
if (!failureAllowed)
FailuresSuppressed++;
return failureAllowed;
}
}
}
}
@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Utils;
@@ -37,13 +38,16 @@ namespace osu.Game.Rulesets.Osu.Edit
[Resolved]
private IEditorChangeHandler? changeHandler { get; set; }
[Resolved]
private EditorBeatmap editorBeatmap { get; set; } = null!;
[Resolved(CanBeNull = true)]
private IDistanceSnapProvider? snapProvider { get; set; }
private BindableList<HitObject> selectedItems { get; } = new BindableList<HitObject>();
[BackgroundDependencyLoader]
private void load(EditorBeatmap editorBeatmap)
private void load()
{
selectedItems.BindTo(editorBeatmap.SelectedHitObjects);
}
@@ -53,15 +57,22 @@ namespace osu.Game.Rulesets.Osu.Edit
base.LoadComplete();
selectedItems.CollectionChanged += (_, __) => updateState();
editorBeatmap.HitObjectUpdated += hitObjectUpdated;
updateState();
}
private void hitObjectUpdated(HitObject hitObject)
{
if (selectedMovableObjects.Contains(hitObject))
updateState();
}
private void updateState()
{
var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects);
CanScaleX.Value = quad.Width > 0;
CanScaleY.Value = quad.Height > 0;
CanScaleX.Value = Precision.DefinitelyBigger(quad.Width, 0);
CanScaleY.Value = Precision.DefinitelyBigger(quad.Height, 0);
CanScaleDiagonally.Value = CanScaleX.Value && CanScaleY.Value;
CanScaleFromPlayfieldOrigin.Value = selectedMovableObjects.Any();
IsScalingSlider.Value = selectedMovableObjects.Count() == 1 && selectedMovableObjects.First() is Slider;
@@ -339,5 +350,13 @@ namespace osu.Game.Rulesets.Osu.Edit
PathControlPointTypes = (hitObject as IHasPath)?.Path.ControlPoints.Select(p => p.Type).ToArray();
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (editorBeatmap.IsNotNull())
editorBeatmap.HitObjectUpdated -= hitObjectUpdated;
}
}
}
@@ -11,7 +11,6 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Filter;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Screens.Select.Filter;
namespace osu.Game.Tests.NonVisual.Filtering
@@ -588,6 +587,26 @@ namespace osu.Game.Tests.NonVisual.Filtering
Assert.That(visibleBeatmaps, Is.EqualTo(expectedBeatmapIndexes));
}
// This is a temporary class that emulates what these tests originally used from song select v1.
// If anyone ever ends up tidying up these test, here's a starting point:
// https://gist.github.com/peppy/67fda38f6483fd1dd01ef845ed5bf932
public class CarouselBeatmap
{
public readonly BeatmapInfo BeatmapInfo;
public BindableBool Filtered = new BindableBool();
public CarouselBeatmap(BeatmapInfo beatmapInfo)
{
BeatmapInfo = beatmapInfo;
}
public void Filter(FilterCriteria criteria)
{
Filtered.Value = !BeatmapCarouselFilterMatching.CheckCriteriaMatch(BeatmapInfo, criteria);
}
}
private class CustomCriteria : IRulesetFilterCriteria
{
private readonly bool match;
@@ -10,7 +10,6 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Filter;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Screens.Select.Filter;
namespace osu.Game.Tests.NonVisual.Filtering
@@ -509,7 +508,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
("Another One", "diff ]with [[ brackets]]]"),
("Diff in title", "a"),
("a", "Diff in diff"),
}).Select(info => new CarouselBeatmap(new BeatmapInfo
}).Select(info => new FilterMatchingTest.CarouselBeatmap(new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
@@ -32,7 +32,7 @@ using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.PlayerSettings;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Storyboards.Drawables;
using osu.Game.Tests.Resources;
using osuTK;
@@ -15,7 +15,7 @@ using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.Metadata;
using osu.Game.Tests.Visual.OnlinePlay;
@@ -1,45 +1,64 @@
// 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.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using System;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Overlays;
using osu.Game.Screens;
using osu.Game.Screens.Edit.Submission;
using osu.Game.Screens.Footer;
namespace osu.Game.Tests.Visual.Editing
{
public partial class TestSceneBeatmapSubmissionOverlay : OsuTestScene
public partial class TestSceneBeatmapSubmissionOverlay : ScreenTestScene
{
private ScreenFooter footer = null!;
private TestBeatmapSubmissionOverlayScreen screen = null!;
[Cached]
private readonly BeatmapSubmissionSettings beatmapSubmissionSettings = new BeatmapSubmissionSettings();
[SetUpSteps]
public void SetUpSteps()
public override void SetUpSteps()
{
AddStep("add overlay", () =>
{
var receptor = new ScreenFooter.BackReceptor();
footer = new ScreenFooter(receptor);
base.SetUpSteps();
Child = new DependencyProvidingContainer
{
RelativeSizeAxes = Axes.Both,
CachedDependencies = new[]
{
(typeof(ScreenFooter), (object)footer),
(typeof(BeatmapSubmissionSettings), new BeatmapSubmissionSettings()),
},
Children = new Drawable[]
{
receptor,
new BeatmapSubmissionOverlay
{
State = { Value = Visibility.Visible, },
},
footer,
}
};
});
AddStep("push screen", () => LoadScreen(screen = new TestBeatmapSubmissionOverlayScreen()));
AddUntilStep("wait until screen is loaded", () => screen.IsLoaded, () => Is.True);
AddStep("show overlay", () => screen.Overlay.Show());
}
private partial class TestBeatmapSubmissionOverlayScreen : OsuScreen
{
public override bool ShowFooter => true;
public BeatmapSubmissionOverlay Overlay = null!;
private IDisposable? overlayRegistration;
[Resolved]
private IOverlayManager? overlayManager { get; set; }
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
[BackgroundDependencyLoader]
private void load()
{
LoadComponent(Overlay = new BeatmapSubmissionOverlay());
}
protected override void LoadComplete()
{
base.LoadComplete();
overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
overlayRegistration?.Dispose();
}
}
}
}
@@ -132,6 +132,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName);
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
AddStep("add effect point", () => EditorBeatmap.ControlPointInfo.Add(500, new EffectControlPoint { KiaiMode = true }));
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[]
{
new HitCircle
@@ -185,6 +186,7 @@ namespace osu.Game.Tests.Visual.Editing
var effectPoint = EditorBeatmap.ControlPointInfo.EffectPoints.Single();
return effectPoint.Time == 500 && effectPoint.KiaiMode && effectPoint.ScrollSpeedBindable.IsDefault;
});
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
@@ -223,6 +225,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = previousDifficultyName = Guid.NewGuid().ToString());
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
AddStep("add effect points", () =>
{
EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 });
@@ -253,6 +256,8 @@ namespace osu.Game.Tests.Visual.Editing
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
});
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
AddAssert("created difficulty has effect points", () =>
{
return EditorBeatmap.ControlPointInfo.EffectPoints.SequenceEqual(new[]
@@ -284,6 +289,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName);
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
AddStep("add effect points", () =>
{
EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 });
@@ -311,6 +317,8 @@ namespace osu.Game.Tests.Visual.Editing
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
});
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
AddAssert("created difficulty has effect points", () =>
{
// since this difficulty is on another ruleset, scroll speed specifications are completely reset,
@@ -344,6 +352,7 @@ namespace osu.Game.Tests.Visual.Editing
StartTime = 1000
}
}));
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
AddStep("set approach rate", () => EditorBeatmap.Difficulty.ApproachRate = 4);
AddStep("set combo colours", () =>
{
@@ -394,6 +403,7 @@ namespace osu.Game.Tests.Visual.Editing
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
});
AddAssert("created difficulty has objects", () => EditorBeatmap.HitObjects.Count == 2);
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
@@ -15,7 +15,7 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Overlays;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
@@ -19,6 +19,7 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Edit.Components.TernaryButtons;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osu.Game.Screens.Edit.Timing;
using osu.Game.Tests.Beatmaps;
@@ -112,6 +113,77 @@ namespace osu.Game.Tests.Visual.Editing
hitObjectHasSampleBank(1, HitSampleInfo.BANK_DRUM);
}
[Test]
public void TestAutoAdditionsBankMatchesNormalBankWhenChangedViaPopover()
{
clickSamplePiece(0);
setBankViaPopover(HitSampleInfo.BANK_SOFT);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT);
toggleAdditionViaPopover(1);
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_SOFT);
setBankViaPopover(HitSampleInfo.BANK_DRUM);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM);
setAdditionBankViaPopover(HitSampleInfo.BANK_NORMAL);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL);
setAdditionBankViaPopover(EditorSelectionHandler.HIT_BANK_AUTO);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM);
}
[Test]
public void TestAutoAdditionsBankMatchesNormalBankWhenChangedViaHotkeys()
{
AddStep("select first object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0]));
AddStep("set soft normal bank", () =>
{
InputManager.PressKey(Key.ShiftLeft);
InputManager.Key(Key.E);
InputManager.ReleaseKey(Key.ShiftLeft);
});
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT);
AddStep("toggle finish", () => InputManager.Key(Key.E));
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_SOFT);
AddStep("set drum normal bank", () =>
{
InputManager.PressKey(Key.ShiftLeft);
InputManager.Key(Key.R);
InputManager.ReleaseKey(Key.ShiftLeft);
});
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM);
AddStep("set normal addition bank", () =>
{
InputManager.PressKey(Key.AltLeft);
InputManager.Key(Key.W);
InputManager.ReleaseKey(Key.AltLeft);
});
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL);
AddStep("set auto addition bank", () =>
{
InputManager.PressKey(Key.AltLeft);
InputManager.Key(Key.Q);
InputManager.ReleaseKey(Key.AltLeft);
});
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM);
}
[Test]
public void TestUndo()
{
@@ -346,7 +418,7 @@ namespace osu.Game.Tests.Visual.Editing
{
for (int i = 0; i < h.Samples.Count; i++)
{
h.Samples[i] = h.Samples[i].With(newBank: HitSampleInfo.BANK_SOFT);
h.Samples[i] = h.Samples[i].With(newBank: HitSampleInfo.BANK_SOFT, newEditorAutoBank: false);
}
}
});
@@ -354,7 +426,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("add whistle addition", () =>
{
foreach (var h in EditorBeatmap.HitObjects)
h.Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, HitSampleInfo.BANK_SOFT));
h.Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, HitSampleInfo.BANK_SOFT, editorAutoBank: false));
});
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
@@ -523,6 +595,172 @@ namespace osu.Game.Tests.Visual.Editing
() => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(expected));
}
[Test]
public void TestNonAutoBankHotkeysDuringPlacementPersistAfterPlacement()
{
AddStep("Clear all objects", () => EditorBeatmap.Clear());
AddStep("Enter placement mode", () => InputManager.Key(Key.Number2));
AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType<HitObjectComposer>().First().ScreenSpaceDrawQuad.Centre));
AddStep("Move to 3000", () => EditorClock.Seek(3000));
AddStep("Press drum bank shortcut", () =>
{
InputManager.PressKey(Key.ShiftLeft);
InputManager.Key(Key.R);
InputManager.ReleaseKey(Key.ShiftLeft);
});
AddAssert($"Placement sample is {HitSampleInfo.BANK_DRUM}",
() => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_DRUM));
AddStep("Press normal addition bank shortcut", () =>
{
InputManager.PressKey(Key.AltLeft);
InputManager.Key(Key.W);
InputManager.ReleaseKey(Key.AltLeft);
});
AddStep("Press finish sample shortcut", () =>
{
InputManager.Key(Key.E);
});
AddAssert($"Placement sample addition is {HitSampleInfo.BANK_NORMAL}",
() => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_NORMAL));
AddStep("Finish placement", () => InputManager.Click(MouseButton.Left));
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL);
hitObjectHasAutoNormalBankFlag(0, false);
hitObjectHasAutoAdditionBankFlag(0, false);
clickSamplePiece(0);
samplePopoverIsOpen();
samplePopoverHasSingleAdditionBank(HitSampleInfo.BANK_NORMAL);
}
[Test]
public void TestAutoAdditionBankHotkeyDuringPlacementPersistsAfterPlacement()
{
AddStep("Clear all objects", () => EditorBeatmap.Clear());
AddStep("Enter placement mode", () => InputManager.Key(Key.Number2));
AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType<HitObjectComposer>().First().ScreenSpaceDrawQuad.Centre));
AddStep("Move to 3000", () => EditorClock.Seek(3000));
AddStep("Press drum bank shortcut", () =>
{
InputManager.PressKey(Key.ShiftLeft);
InputManager.Key(Key.R);
InputManager.ReleaseKey(Key.ShiftLeft);
});
AddAssert($"Placement sample is {HitSampleInfo.BANK_DRUM}",
() => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_DRUM));
AddStep("Press normal addition bank shortcut", () =>
{
InputManager.PressKey(Key.AltLeft);
InputManager.Key(Key.W);
InputManager.ReleaseKey(Key.AltLeft);
});
AddStep("Press finish sample shortcut", () =>
{
InputManager.Key(Key.E);
});
AddStep("Press auto addition bank shortcut", () =>
{
InputManager.PressKey(Key.AltLeft);
InputManager.Key(Key.Q);
InputManager.ReleaseKey(Key.AltLeft);
});
AddAssert($"Placement sample addition is {HitSampleInfo.BANK_DRUM}",
() => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_DRUM));
AddStep("Finish placement", () => InputManager.Click(MouseButton.Left));
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasAutoNormalBankFlag(0, false);
hitObjectHasAutoAdditionBankFlag(0, true);
clickSamplePiece(0);
samplePopoverIsOpen();
samplePopoverHasSingleAdditionBank(EditorSelectionHandler.HIT_BANK_AUTO);
}
[Test]
public void TestFullAutoBankHotkeyDuringPlacementPersistsAfterPlacement()
{
AddStep("Clear all objects", () => EditorBeatmap.Clear());
AddStep("Enter placement mode", () => InputManager.Key(Key.Number2));
AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType<HitObjectComposer>().First().ScreenSpaceDrawQuad.Centre));
AddStep("Move to 3000", () => EditorClock.Seek(3000));
AddStep("Press auto normal bank shortcut", () =>
{
InputManager.PressKey(Key.ShiftLeft);
InputManager.Key(Key.Q);
InputManager.ReleaseKey(Key.ShiftLeft);
});
AddAssert($"Placement sample is {HitSampleInfo.BANK_NORMAL}",
() => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_NORMAL));
AddStep("Press finish sample shortcut", () =>
{
InputManager.Key(Key.E);
});
AddStep("Press auto addition bank shortcut", () =>
{
InputManager.PressKey(Key.AltLeft);
InputManager.Key(Key.Q);
InputManager.ReleaseKey(Key.AltLeft);
});
AddAssert($"Placement sample addition is {HitSampleInfo.BANK_NORMAL}",
() => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_NORMAL));
AddStep("Finish placement", () => InputManager.Click(MouseButton.Left));
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL);
hitObjectHasAutoNormalBankFlag(0, false); // it's the first object - nothing to inherit bank from
hitObjectHasAutoAdditionBankFlag(0, true);
clickSamplePiece(0);
samplePopoverIsOpen();
samplePopoverHasSingleBank(HitSampleInfo.BANK_NORMAL);
samplePopoverHasSingleAdditionBank(EditorSelectionHandler.HIT_BANK_AUTO);
dismissPopover();
AddStep("Move to 5000", () => EditorClock.Seek(5000));
AddStep("Enter placement mode", () => InputManager.Key(Key.Number2));
AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType<HitObjectComposer>().First().ScreenSpaceDrawQuad.Centre));
AddStep("Finish placement", () => InputManager.Click(MouseButton.Left));
hitObjectHasSamples(1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); // finish is still implied, continuing from first placement
hitObjectHasSampleNormalBank(1, HitSampleInfo.BANK_NORMAL);
hitObjectHasSampleAdditionBank(1, HitSampleInfo.BANK_NORMAL);
hitObjectHasAutoNormalBankFlag(1, true);
hitObjectHasAutoAdditionBankFlag(1, true);
clickSamplePiece(1);
samplePopoverIsOpen();
samplePopoverHasSingleBank(HitSampleInfo.BANK_NORMAL);
samplePopoverHasSingleAdditionBank(EditorSelectionHandler.HIT_BANK_AUTO);
}
[Test]
public void PopoverForMultipleSelectionChangesAllSamples()
{
@@ -599,19 +837,19 @@ namespace osu.Game.Tests.Visual.Editing
Path = new SliderPath(new[] { new PathControlPoint(Vector2.Zero), new PathControlPoint(new Vector2(250, 0)) }),
Samples =
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, editorAutoBank: false)
},
NodeSamples = new List<IList<HitSampleInfo>>
{
new List<HitSampleInfo>
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_DRUM),
new HitSampleInfo(HitSampleInfo.HIT_CLAP, bank: HitSampleInfo.BANK_DRUM),
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_DRUM, editorAutoBank: false),
new HitSampleInfo(HitSampleInfo.HIT_CLAP, bank: HitSampleInfo.BANK_DRUM, editorAutoBank: false),
},
new List<HitSampleInfo>
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_SOFT),
new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_SOFT),
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_SOFT, editorAutoBank: false),
new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_SOFT, editorAutoBank: false),
},
}
});
@@ -880,6 +1118,14 @@ namespace osu.Game.Tests.Visual.Editing
return dropdown?.Current.Value == "(multiple)";
});
private void samplePopoverHasSingleAdditionBank(string bank) => AddUntilStep($"sample popover has bank {bank}", () =>
{
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault();
var dropdown = popover?.ChildrenOfType<LabelledDropdown<string>>().ElementAt(1);
return dropdown?.Current.Value == bank;
});
private void dismissPopover()
{
AddStep("dismiss popover", () => InputManager.Key(Key.Escape));
@@ -953,6 +1199,18 @@ namespace osu.Game.Tests.Visual.Editing
return h.Samples.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(o => o.Bank == bank);
});
private void hitObjectHasAutoNormalBankFlag(int objectIndex, bool autoBank) => AddAssert($"{objectIndex.ToOrdinalWords()} has auto normal bank {(autoBank ? "on" : "off")}", () =>
{
var h = EditorBeatmap.HitObjects.ElementAt(objectIndex);
return h.Samples.Where(o => o.Name == HitSampleInfo.HIT_NORMAL).All(o => o.EditorAutoBank == autoBank);
});
private void hitObjectHasAutoAdditionBankFlag(int objectIndex, bool autoBank) => AddAssert($"{objectIndex.ToOrdinalWords()} has auto addition bank {(autoBank ? "on" : "off")}", () =>
{
var h = EditorBeatmap.HitObjects.ElementAt(objectIndex);
return h.Samples.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(o => o.EditorAutoBank == autoBank);
});
private void hitObjectNodeHasSamples(int objectIndex, int nodeIndex, params string[] samples) => AddAssert(
$"{objectIndex.ToOrdinalWords()} object {nodeIndex.ToOrdinalWords()} node has samples {string.Join(',', samples)}", () =>
{
@@ -14,7 +14,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Menu;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.Editing
@@ -272,8 +272,8 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("circle has 2 samples", () => EditorBeatmap.HitObjects[1].Samples, () => Has.Count.EqualTo(2));
AddAssert("normal sample has soft bank", () => EditorBeatmap.HitObjects[1].Samples.Single(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank,
() => Is.EqualTo(HitSampleInfo.BANK_SOFT));
AddAssert("clap sample has drum bank", () => EditorBeatmap.HitObjects[1].Samples.Single(s => s.Name == HitSampleInfo.HIT_CLAP).Bank,
() => Is.EqualTo(HitSampleInfo.BANK_DRUM));
AddAssert("clap sample has soft bank", () => EditorBeatmap.HitObjects[1].Samples.Single(s => s.Name == HitSampleInfo.HIT_CLAP).Bank,
() => Is.EqualTo(HitSampleInfo.BANK_SOFT));
AddAssert("circle inherited volume", () => EditorBeatmap.HitObjects[1].Samples.All(s => s.Volume == 70));
AddStep("seek to 1000", () => EditorClock.Seek(1000)); // previous object is the one at time 500, which has no additions
@@ -19,7 +19,7 @@ using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelect
namespace osu.Game.Tests.Visual.Gameplay
{
public partial class TestSceneBeatmapMetadataDisplay : OsuTestScene
{
@@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Gameplay
@@ -21,7 +21,7 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Tests.Gameplay;
using osuTK.Graphics;
@@ -25,7 +25,7 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Skinning;
using osu.Game.Tests.Gameplay;
using osu.Game.Tests.Visual.Spectator;
@@ -15,7 +15,7 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Tests.Gameplay;
using osuTK.Input;
@@ -21,7 +21,7 @@ using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Skinning;
using osu.Game.Tests.Gameplay;
@@ -10,7 +10,7 @@ using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Tests.Gameplay;
namespace osu.Game.Tests.Visual.Gameplay
@@ -6,16 +6,16 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Online.API.Requests.Responses;
using osuTK.Graphics;
using osu.Game.Online.Leaderboards;
using osu.Game.Overlays;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Users;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.SongSelect
namespace osu.Game.Tests.Visual.Gameplay
{
public partial class TestSceneUserTopScoreContainer : OsuTestScene
{
@@ -21,7 +21,7 @@ using osu.Game.Online.Spectator;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -1,6 +1,8 @@
// 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;
@@ -15,6 +17,7 @@ using osu.Game.Database;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Lounge;
@@ -22,6 +25,7 @@ using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Screens.Play;
using osu.Game.Tests.Resources;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -35,7 +39,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
protected IScreen CurrentScreen => multiplayerComponents.CurrentScreen;
protected IScreen CurrentSubScreen => multiplayerComponents.MultiplayerScreen.CurrentSubScreen;
private BeatmapManager beatmaps = null!;
protected BeatmapManager Beatmaps { get; private set; } = null!;
private BeatmapSetInfo importedSet = null!;
private RulesetStore rulesets = null!;
@@ -49,7 +54,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
BeatmapStore beatmapStore;
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore());
Dependencies.Cache(Realm);
@@ -62,13 +67,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
Beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
Realm.Write(r =>
{
foreach (var beatmapInfo in r.All<BeatmapInfo>())
beatmapInfo.OnlineMD5Hash = beatmapInfo.MD5Hash;
});
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
importedSet = Beatmaps.GetAllUsableBeatmapSets().First();
InitialBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0);
OtherBeatmap = importedSet.Beatmaps.Last(b => b.Ruleset.OnlineID == 0);
});
@@ -118,6 +123,30 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("exit player", () => multiplayerComponents.MultiplayerScreen.MakeCurrent());
}
protected void AddBeatmapFromSongSelect(Func<BeatmapInfo> beatmap, RulesetInfo? ruleset = null, IReadOnlyList<Mod>? mods = null)
{
Screens.Select.SongSelect? songSelect = null;
AddStep("click add button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerMatchSubScreen.AddItemButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null);
AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering);
if (ruleset != null)
AddStep($"set {ruleset.Name} ruleset", () => songSelect.AsNonNull().Ruleset.Value = ruleset);
if (mods != null)
AddStep($"set mods to {string.Join(",", mods.Select(m => m.Acronym))}", () => songSelect.AsNonNull().Mods.Value = mods);
AddStep("select other beatmap", () => songSelect.AsNonNull().Beatmap.Value = Beatmaps.GetWorkingBeatmap(beatmap()));
AddStep("confirm selection", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
@@ -1,24 +1,16 @@
// 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.Extensions.ObjectExtensions;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Screens.Play;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -45,10 +37,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestItemAddedToTheEndOfQueue()
{
addItem(() => OtherBeatmap);
AddBeatmapFromSongSelect(() => OtherBeatmap);
AddUntilStep("playlist has 2 items", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 2);
addItem(() => InitialBeatmap);
AddBeatmapFromSongSelect(() => InitialBeatmap);
AddUntilStep("playlist has 3 items", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 3);
AddUntilStep("first item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
@@ -57,8 +49,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestNextItemSelectedAfterGameplayFinish()
{
addItem(() => OtherBeatmap);
addItem(() => InitialBeatmap);
AddBeatmapFromSongSelect(() => OtherBeatmap);
AddBeatmapFromSongSelect(() => InitialBeatmap);
RunGameplay();
@@ -74,8 +66,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestItemsNotClearedWhenSwitchToHostOnlyMode()
{
addItem(() => OtherBeatmap);
addItem(() => InitialBeatmap);
AddBeatmapFromSongSelect(() => OtherBeatmap);
AddBeatmapFromSongSelect(() => InitialBeatmap);
// Move to the "other" beatmap.
RunGameplay();
@@ -89,14 +81,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestCorrectItemSelectedAfterNewItemAdded()
{
addItem(() => OtherBeatmap);
AddBeatmapFromSongSelect(() => OtherBeatmap);
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
}
[Test]
public void TestCorrectRulesetSelectedAfterNewItemAdded()
{
addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo);
AddBeatmapFromSongSelect(() => OtherBeatmap, new CatchRuleset().RulesetInfo);
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle);
@@ -113,7 +105,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestCorrectModsSelectedAfterNewItemAdded()
{
addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() });
AddBeatmapFromSongSelect(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() });
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle);
@@ -126,28 +118,5 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("mods are correct", () => !((Player)CurrentScreen).Mods.Value.Any());
AddStep("exit player", () => CurrentScreen.Exit());
}
private void addItem(Func<BeatmapInfo> beatmap, RulesetInfo? ruleset = null, IReadOnlyList<Mod>? mods = null)
{
Screens.Select.SongSelect? songSelect = null;
AddStep("click add button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerMatchSubScreen.AddItemButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null);
AddUntilStep("wait for loaded", () => songSelect.AsNonNull().BeatmapSetsLoaded);
if (ruleset != null)
AddStep($"set {ruleset.Name} ruleset", () => songSelect.AsNonNull().Ruleset.Value = ruleset);
if (mods != null)
AddStep($"set mods to {string.Join(",", mods.Select(m => m.Acronym))}", () => songSelect.AsNonNull().Mods.Value = mods);
AddStep("select other beatmap", () => songSelect.AsNonNull().FinaliseSelection(beatmap()));
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
}
}
}
@@ -7,14 +7,13 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Framework.Testing;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens;
using osu.Game.Screens.Footer;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Utils;
@@ -22,12 +21,13 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneFreeModSelectOverlay : MultiplayerTestScene
public partial class TestSceneFreeModSelectOverlay : ScreenTestScene
{
private FreeModSelectOverlay freeModSelectOverlay = null!;
private FooterButtonFreeMods footerButtonFreeMods = null!;
private ScreenFooter footer = null!;
private TestFreeModSelectOverlayScreen screen = null!;
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
private readonly Bindable<IReadOnlyList<Mod>> freeMods = new Bindable<IReadOnlyList<Mod>>([]);
private FreeModSelectOverlay freeModSelectOverlay => screen.Overlay;
[BackgroundDependencyLoader]
private void load(OsuGameBase osuGameBase)
@@ -35,6 +35,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
availableMods.BindTo(osuGameBase.AvailableMods);
}
[SetUpSteps]
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("reset selected mods", () => freeMods.Value = []);
}
[Test]
public void TestFreeModSelect()
{
@@ -44,11 +52,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
() => this.ChildrenOfType<ModPanel>()
.Where(panel => panel.IsPresent)
.All(panel => panel.Mod.HasImplementation && panel.Mod.UserPlayable));
AddToggleStep("toggle visibility", visible =>
{
freeModSelectOverlay.State.Value = visible ? Visibility.Visible : Visibility.Hidden;
});
}
[Test]
@@ -72,18 +75,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("select all button enabled", () => this.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
AddStep("click select all button", navigateAndClick<SelectAllModsButton>);
AddStep("click select all button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<SelectAllModsButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddAssert("select all button disabled", () => !this.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
AddStep("change search term", () => freeModSelectOverlay.SearchTerm = "e");
AddAssert("select all button enabled", () => this.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
void navigateAndClick<T>() where T : Drawable
{
InputManager.MoveMouseTo(this.ChildrenOfType<T>().Single());
InputManager.Click(MouseButton.Left);
}
}
[Test]
@@ -124,55 +125,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("select all button enabled", () => this.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
}
[Test]
public void TestSelectAllViaFooterButtonThenDeselectFromOverlay()
{
createFreeModSelect();
AddAssert("overlay select all button enabled", () => this.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
AddAssert("footer button displays off", () => footerButtonFreeMods.ChildrenOfType<IHasText>().Any(t => t.Text == "off"));
AddStep("click footer select all button", () =>
{
InputManager.MoveMouseTo(footerButtonFreeMods);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("all mods selected", assertAllAvailableModsSelected);
AddAssert("footer button displays all", () => footerButtonFreeMods.ChildrenOfType<IHasText>().Any(t => t.Text == "all"));
AddStep("click deselect all button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<DeselectAllModsButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddUntilStep("all mods deselected", () => !freeModSelectOverlay.SelectedMods.Value.Any());
AddAssert("footer button displays off", () => footerButtonFreeMods.ChildrenOfType<IHasText>().Any(t => t.Text == "off"));
}
private void createFreeModSelect()
{
AddStep("create free mod select screen", () => Child = new DependencyProvidingContainer
AddStep("create free mod select screen", () => LoadScreen(screen = new TestFreeModSelectOverlayScreen
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
freeModSelectOverlay = new FreeModSelectOverlay
{
State = { Value = Visibility.Visible }
},
footerButtonFreeMods = new FooterButtonFreeMods(freeModSelectOverlay)
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Y = -ScreenFooter.HEIGHT,
FreeMods = { BindTarget = freeModSelectOverlay.SelectedMods },
},
footer = new ScreenFooter(),
},
CachedDependencies = new (Type, object)[] { (typeof(ScreenFooter), footer) },
});
FreeMods = { BindTarget = freeMods },
}));
AddUntilStep("wait until screen is loaded", () => screen.IsLoaded, () => Is.True);
AddStep("show overlay", () => freeModSelectOverlay.Show());
AddUntilStep("all column content loaded",
() => freeModSelectOverlay.ChildrenOfType<ModColumn>().Any()
&& freeModSelectOverlay.ChildrenOfType<ModColumn>().All(column => column.IsLoaded && column.ItemsLoaded));
@@ -197,5 +157,50 @@ namespace osu.Game.Tests.Visual.Multiplayer
return true;
}
private partial class TestFreeModSelectOverlayScreen : OsuScreen
{
public override bool ShowFooter => true;
public FreeModSelectOverlay Overlay = null!;
private IDisposable? overlayRegistration;
public readonly Bindable<IReadOnlyList<Mod>> FreeMods = new Bindable<IReadOnlyList<Mod>>([]);
[Resolved]
private IOverlayManager? overlayManager { get; set; }
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
[BackgroundDependencyLoader]
private void load()
{
LoadComponent(Overlay = new FreeModSelectOverlay
{
SelectedMods = { BindTarget = FreeMods }
});
}
protected override void LoadComplete()
{
base.LoadComplete();
overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay);
}
public override IReadOnlyList<ScreenFooterButton> CreateFooterButtons() =>
[
new FooterButtonFreeMods(Overlay)
{
FreeMods = { BindTarget = FreeMods },
},
];
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
overlayRegistration?.Dispose();
}
}
}
}
@@ -5,6 +5,8 @@ using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
@@ -36,6 +38,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("second playlist item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[1].ID);
}
[Test]
public void TestItemStillSelectedAfterChangeToSameBeatmap()
{
selectNewItem(() => InitialBeatmap);
AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
public void TestSettingsUpdatedWhenChangingQueueMode()
{
@@ -47,14 +57,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("api room updated", () => MultiplayerClient.ClientAPIRoom?.QueueMode == QueueMode.AllPlayers);
}
[Test]
public void TestItemStillSelectedAfterChangeToSameBeatmap()
{
selectNewItem(() => InitialBeatmap);
AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
public void TestItemStillSelectedAfterChangeToOtherBeatmap()
{
@@ -80,13 +82,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestAddItemsAsHost()
{
addItem(() => OtherBeatmap);
AddBeatmapFromSongSelect(() => OtherBeatmap);
AddUntilStep("playlist contains two items", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 2);
}
private void selectNewItem(Func<BeatmapInfo> beatmap)
{
Screens.Select.SongSelect? songSelect = null;
AddUntilStep("wait for playlist panels to load", () =>
{
var queueList = this.ChildrenOfType<MultiplayerQueueList>().Single();
@@ -99,26 +103,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded);
AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null);
AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering);
BeatmapInfo otherBeatmap = null!;
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap()));
AddStep("select other beatmap", () => songSelect.AsNonNull().Beatmap.Value = Beatmaps.GetWorkingBeatmap(otherBeatmap = beatmap()));
AddStep("confirm selection", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
AddUntilStep("selected item is new beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == otherBeatmap.OnlineID);
}
private void addItem(Func<BeatmapInfo> beatmap)
{
AddStep("click add button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerMatchSubScreen.AddItemButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded);
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(beatmap()));
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
}
}
}
@@ -1,52 +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.Linq;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual.OnlinePlay;
using osuTK;
namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneMatchBeatmapDetailArea : OnlinePlayTestScene
{
private Room room = null!;
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("create area", () =>
{
Child = new MatchBeatmapDetailArea(room = new Room())
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500),
CreateNewItem = createNewItem
};
});
}
private void createNewItem()
{
room.Playlist = room.Playlist.Append(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
ID = room.Playlist.Count,
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
{
new APIMod(new OsuModHardRock()),
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
}).ToArray();
}
}
}
@@ -10,7 +10,7 @@ using osu.Framework.Timing;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -228,7 +228,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
// edit playlist item
AddStep("Press select", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for song select", () => InputManager.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
waitForSongSelect();
// select beatmap
AddStep("Press select", () => InputManager.Key(Key.Enter));
@@ -451,7 +451,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
waitForSongSelect();
AddUntilStep("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == multiplayerClient.ClientRoom?.Playlist.First().BeatmapID);
@@ -492,7 +492,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
waitForSongSelect();
AddUntilStep("Ruleset matches current item", () => Ruleset.Value.OnlineID == multiplayerClient.ClientRoom?.Playlist.First().RulesetID);
@@ -533,7 +533,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
waitForSongSelect();
AddUntilStep("Mods match current item",
() => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(multiplayerClient.ClientRoom.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
@@ -1051,7 +1051,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("press edit on second item", () => this.ChildrenOfType<DrawableRoomPlaylistItem>().Single(i => i.Item.RulesetID == 1)
.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistEditButton>().Single().TriggerClick());
AddUntilStep("wait for song select", () => InputManager.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
waitForSongSelect();
AddAssert("ruleset is taiko", () => Ruleset.Value.OnlineID == 1);
AddStep("start match", () => multiplayerClient.StartMatch().WaitSafely());
@@ -1249,6 +1249,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
}
private void waitForSongSelect()
{
AddUntilStep("wait for song select", () =>
{
var songSelect = InputManager.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault();
return songSelect != null && songSelect.IsCurrentScreen() && !songSelect.IsFiltering;
});
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
@@ -9,7 +9,7 @@ using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -7,7 +7,7 @@ using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -16,6 +16,7 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
@@ -26,8 +27,8 @@ using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -64,7 +65,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
base.SetUpSteps();
AddStep("create room", () => room = CreateDefaultRoom());
AddStep("create room", () =>
{
Ruleset.Value = new OsuRuleset().RulesetInfo;
room = CreateDefaultRoom();
});
AddStep("join room", () => JoinRoom(room));
WaitForJoined();
}
@@ -80,7 +85,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
LoadScreen(songSelect = new TestMultiplayerMatchSongSelect(room));
});
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded);
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && !songSelect.IsFiltering);
}
[Test]
@@ -101,19 +106,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
setUp();
AddStep("change ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
AddUntilStep("wait for filtering", () => !songSelect.IsFiltering);
AddStep("select beatmap",
() => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == new TaikoRuleset().LegacyID)));
() => songSelect.SelectBeatmap(selectedBeatmap = beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == new TaikoRuleset().LegacyID)));
AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
AddUntilStep("wait for ongoing operation to complete", () => !OnlinePlayDependencies.OngoingOperationTracker.InProgress.Value);
AddStep("set mods", () => SelectedMods.Value = new[] { new TaikoModDoubleTime() });
AddStep("confirm selection", () => songSelect.FinaliseSelection());
AddStep("confirm selection", () => InputManager.Key(Key.Enter));
AddUntilStep("song select exited", () => !songSelect.IsCurrentScreen());
AddAssert("beatmap not changed", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
AddAssert("beatmap not changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo((selectedBeatmap)));
AddAssert("ruleset not changed", () => Ruleset.Value.Equals(new TaikoRuleset().RulesetInfo));
AddAssert("mods not changed", () => SelectedMods.Value.Single() is TaikoModDoubleTime);
}
@@ -133,10 +140,42 @@ namespace osu.Game.Tests.Visual.Multiplayer
// A previous test's mod overlay could still be fading out.
AddUntilStep("wait for only one freemod overlay", () => this.ChildrenOfType<FreeModSelectOverlay>().Count() == 1);
AddStep("open free mod overlay", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreeMods>().Single());
InputManager.Click(MouseButton.Left);
});
assertFreeModNotShown(allowedMod);
assertFreeModNotShown(requiredMod);
}
[Test]
public void TestFreeModsDisplayedOnEnter()
{
AddStep("set room freemods", () =>
{
var editedItem = MultiplayerClient.ClientRoom!.CurrentPlaylistItem.Clone();
editedItem.AllowedMods =
[
new APIMod(new OsuModHardRock()),
];
MultiplayerClient.EditPlaylistItem(editedItem);
});
setUp();
AddStep("open free mod overlay", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreeMods>().Single());
InputManager.Click(MouseButton.Left);
});
assertFreeModShown(typeof(OsuModHardRock));
}
[Test]
public void TestChangeRulesetImmediatelyAfterLoadComplete()
{
@@ -154,16 +193,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
songSelect.OnLoadComplete += _ => Ruleset.Value = new TaikoRuleset().RulesetInfo;
LoadScreen(songSelect);
});
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded);
AddStep("confirm selection", () => songSelect.FinaliseSelection());
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && !songSelect.IsFiltering);
AddStep("confirm selection", () => InputManager.Key(Key.Enter));
AddAssert("beatmap is taiko", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID, () => Is.EqualTo(1));
AddAssert("ruleset is taiko", () => Ruleset.Value.OnlineID, () => Is.EqualTo(1));
}
private void assertFreeModShown(Type type)
{
AddUntilStep($"{type.ReadableName()} displayed in freemod overlay",
() => this.ChildrenOfType<FreeModSelectOverlay>()
.Single()
.ChildrenOfType<ModPanel>()
.Where(panel => panel.Visible)
.Any(b => b.Mod.GetType() == type));
}
private void assertFreeModNotShown(Type type)
{
AddAssert($"{type.ReadableName()} not displayed in freemod overlay",
AddUntilStep($"{type.ReadableName()} not displayed in freemod overlay",
() => this.ChildrenOfType<FreeModSelectOverlay>()
.Single()
.ChildrenOfType<ModPanel>()
@@ -185,12 +235,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
public new Bindable<IReadOnlyList<Mod>> FreeMods => base.FreeMods;
public new BeatmapCarousel Carousel => base.Carousel;
public TestMultiplayerMatchSongSelect(Room room, PlaylistItem? itemToEdit = null)
: base(room, itemToEdit)
{
}
public void SelectBeatmap(BeatmapInfo beatmap) => SelectAndRun(beatmap, () => { });
}
}
}
@@ -12,7 +12,7 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.Play;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Tests.Gameplay;
namespace osu.Game.Tests.Visual.Multiplayer
@@ -27,7 +27,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestScenePlaylistsSongSelectV2 : OnlinePlayTestScene
public partial class TestScenePlaylistsSongSelect : OnlinePlayTestScene
{
private RulesetStore rulesets = null!;
private BeatmapManager manager = null!;
@@ -164,20 +164,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("freestyle enabled", () => songSelect.Freestyle.Value, () => Is.True);
AddStep("click icon in free mods button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreeModsV2>().Single());
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreeMods>().Single());
InputManager.Click(MouseButton.Left);
});
AddAssert("mod select not visible", () => this.ChildrenOfType<FreeModSelectOverlay>().Single().State.Value, () => Is.EqualTo(Visibility.Hidden));
AddStep("toggle freestyle off", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreestyleV2>().Single());
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreestyle>().Single());
InputManager.Click(MouseButton.Left);
});
AddAssert("freestyle disabled", () => songSelect.Freestyle.Value, () => Is.False);
AddStep("click icon in free mods button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreeModsV2>().Single());
InputManager.MoveMouseTo(this.ChildrenOfType<FooterButtonFreeMods>().Single());
InputManager.Click(MouseButton.Left);
});
AddAssert("mod select visible", () => this.ChildrenOfType<FreeModSelectOverlay>().Single().State.Value, () => Is.EqualTo(Visibility.Visible));
@@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
rulesets.Dispose();
}
private partial class TestPlaylistsSongSelect : PlaylistsSongSelectV2
private partial class TestPlaylistsSongSelect : PlaylistsSongSelect
{
public new IBindable<bool> Freestyle => base.Freestyle;
@@ -26,8 +26,8 @@ using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.GameplayTest;
using osu.Game.Screens.Edit.Setup;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
using osuTK.Input;
@@ -5,7 +5,7 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Screens.Menu;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Navigation
@@ -15,7 +15,7 @@ using osu.Game.Input.Bindings;
using osu.Game.Overlays.Settings.Sections.Input;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps.IO;
using osuTK.Input;
@@ -5,7 +5,7 @@ using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Game.Configuration;
using osu.Game.Screens.Play;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps.IO;
using osuTK.Input;
@@ -17,7 +17,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps.IO;
using osuTK.Input;
@@ -16,7 +16,7 @@ using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Menu;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.Navigation
{
@@ -18,8 +18,8 @@ using osu.Game.Screens;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.SelectV2;
using FilterControl = osu.Game.Screens.SelectV2.FilterControl;
using osu.Game.Screens.Select;
using FilterControl = osu.Game.Screens.Select.FilterControl;
namespace osu.Game.Tests.Visual.Navigation
{
@@ -8,9 +8,13 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Screens;
using osu.Game.Screens.Footer;
@@ -23,10 +27,13 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestFooterButtonsOnScreenTransitions()
{
PushAndConfirm(() => new TestScreenOne());
PushAndConfirm(() => new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }]
});
AddUntilStep("button one shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button One"));
PushAndConfirm(() => new TestScreenTwo());
PushAndConfirm(() => new TestScreen { CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }] });
AddUntilStep("button two shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button Two"));
AddStep("exit screen", () => Game.ScreenStack.Exit());
@@ -40,7 +47,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("footer hidden", () => screenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden));
AddAssert("old back button shown", () => Game.BackButton.State.Value, () => Is.EqualTo(Visibility.Visible));
PushAndConfirm(() => new TestScreen(true));
PushAndConfirm(() => new TestScreen());
AddAssert("footer shown", () => screenFooter.State.Value, () => Is.EqualTo(Visibility.Visible));
AddAssert("old back button hidden", () => Game.BackButton.State.Value, () => Is.EqualTo(Visibility.Hidden));
@@ -69,10 +76,16 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("footer hidden", () => screenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden));
AddAssert("old back button shown", () => Game.BackButton.State.Value, () => Is.EqualTo(Visibility.Visible));
pushSubScreenAndConfirm(() => screen, () => new TestScreenOne());
pushSubScreenAndConfirm(() => screen, () => new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }]
});
AddUntilStep("button one shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button One"));
pushSubScreenAndConfirm(() => screen, () => new TestScreenTwo());
pushSubScreenAndConfirm(() => screen, () => new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }]
});
AddUntilStep("button two shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button Two"));
AddStep("exit sub screen", () => screen.ExitSubScreen());
@@ -92,10 +105,16 @@ namespace osu.Game.Tests.Visual.Navigation
TestScreenWithSubScreen screen = null!;
PushAndConfirm(() => screen = new TestScreenWithSubScreen());
pushSubScreenAndConfirm(() => screen, () => new TestScreenOne());
pushSubScreenAndConfirm(() => screen, () => new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }]
});
AddUntilStep("button one shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button One"));
PushAndConfirm(() => new TestScreenTwo());
PushAndConfirm(() => new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }]
});
AddUntilStep("button two shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button Two"));
AddStep("exit parent screen", () => Game.ScreenStack.Exit());
@@ -111,14 +130,23 @@ namespace osu.Game.Tests.Visual.Navigation
TestScreenWithSubScreen screen = null!;
PushAndConfirm(() => screen = new TestScreenWithSubScreen());
pushSubScreenAndConfirm(() => screen, () => new TestScreenOne());
pushSubScreenAndConfirm(() => screen, () => new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }]
});
AddUntilStep("button one shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button One"));
PushAndConfirm(() => new TestScreenOne());
PushAndConfirm(() => new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }]
});
AddUntilStep("button one shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button One"));
// Can't use the helper method because the screen never loads
AddStep("Push new sub screen", () => screen.PushSubScreen(new TestScreenTwo()));
AddStep("Push new sub screen", () => screen.PushSubScreen(new TestScreen
{
CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }]
}));
AddWaitStep("wait for potential screen load", 5);
AddUntilStep("button one still shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button One"));
@@ -126,6 +154,83 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("button two shown", () => screenFooter.ChildrenOfType<ScreenFooterButton>().First().Text.ToString(), () => Is.EqualTo("Button Two"));
}
/// <summary>
/// Tests clicking the back button while an overlay is open.
/// </summary>
[Test]
public void TestBackButtonWhenOverlayOpen()
{
TestScreen screen = null!;
PushAndConfirm(() =>
{
ShearedOverlayContainer overlay = new TestShearedOverlayContainer();
return screen = new TestScreen
{
Overlay = overlay,
CreateButtons = () =>
[
new ScreenFooterButton(overlay)
{
AccentColour = Dependencies.Get<OsuColour>().Orange1,
Icon = FontAwesome.Solid.Toolbox,
Text = "One",
},
new ScreenFooterButton { Text = "Two", Action = () => { } },
new ScreenFooterButton { Text = "Three", Action = () => { } },
],
};
});
AddStep("show overlay", () => screen.Overlay.Show());
AddAssert("overlay shown", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Visible));
AddStep("press back", () => screenFooter.ChildrenOfType<ScreenBackButton>().Single().TriggerClick());
AddAssert("overlay hidden", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Hidden));
AddAssert("screen still shown", () => screen.IsCurrentScreen(), () => Is.True);
}
/// <summary>
/// Tests clicking the back button on an overlay with `BackButtonPressed` being overridden.
/// </summary>
[Test]
public void TestBackButtonWithCustomBackButtonPressed()
{
TestScreen screen = null!;
TestShearedOverlayContainer overlay = null!;
PushAndConfirm(() =>
{
return screen = new TestScreen
{
Overlay = overlay = new TestShearedOverlayContainer(),
CreateButtons = () =>
[
new ScreenFooterButton(overlay)
{
AccentColour = Dependencies.Get<OsuColour>().Orange1,
Icon = FontAwesome.Solid.Toolbox,
Text = "One",
},
new ScreenFooterButton { Text = "Two", Action = () => { } },
new ScreenFooterButton { Text = "Three", Action = () => { } },
],
};
});
AddStep("show overlay", () => screen.Overlay.Show());
AddAssert("overlay shown", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Visible));
AddStep("set block count", () => overlay.BackButtonCount = 1);
AddStep("press back", () => screenFooter.ChildrenOfType<ScreenBackButton>().Single().TriggerClick());
AddAssert("overlay still shown", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Visible));
AddStep("press back again", () => screenFooter.ChildrenOfType<ScreenBackButton>().Single().TriggerClick());
AddAssert("overlay hidden", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Hidden));
AddAssert("screen still shown", () => screen.IsCurrentScreen(), () => Is.True);
}
private void pushSubScreenAndConfirm(Func<TestScreenWithSubScreen> target, Func<Screen> newScreen)
{
Screen screen = null!;
@@ -142,39 +247,45 @@ namespace osu.Game.Tests.Visual.Navigation
&& (previousScreen == null || previousScreen.GetChildScreen() == screen));
}
private partial class TestScreenOne : OsuScreen
{
public override bool ShowFooter => true;
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
public override IReadOnlyList<ScreenFooterButton> CreateFooterButtons() => new[]
{
new ScreenFooterButton { Text = "Button One" },
};
}
private partial class TestScreenTwo : OsuScreen
{
public override bool ShowFooter => true;
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
public override IReadOnlyList<ScreenFooterButton> CreateFooterButtons() => new[]
{
new ScreenFooterButton { Text = "Button Two" },
};
}
private partial class TestScreen : OsuScreen
{
public override bool ShowFooter { get; }
public TestScreen(bool footer)
public Func<IReadOnlyList<ScreenFooterButton>> CreateButtons = Array.Empty<ScreenFooterButton>;
public ShearedOverlayContainer Overlay = new TestShearedOverlayContainer();
private IDisposable? overlayRegistration;
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
[Resolved]
private IOverlayManager? overlayManager { get; set; }
public TestScreen(bool showFooter = true)
{
ShowFooter = footer;
ShowFooter = showFooter;
}
[BackgroundDependencyLoader]
private void load()
{
LoadComponent(Overlay);
}
protected override void LoadComplete()
{
base.LoadComplete();
overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay);
}
public override IReadOnlyList<ScreenFooterButton> CreateFooterButtons() => CreateButtons.Invoke();
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
overlayRegistration?.Dispose();
}
}
@@ -196,5 +307,66 @@ namespace osu.Game.Tests.Visual.Navigation
public void ExitSubScreen() => SubScreenStack.Exit();
}
private partial class TestShearedOverlayContainer : ShearedOverlayContainer
{
public TestShearedOverlayContainer()
: base(OverlayColourScheme.Orange)
{
}
[BackgroundDependencyLoader]
private void load()
{
Header.Title = "Test overlay";
Header.Description = "An overlay that is made purely for testing purposes.";
}
public int BackButtonCount;
public override bool OnBackButton()
{
if (BackButtonCount > 0)
{
BackButtonCount--;
return true;
}
return false;
}
public override VisibilityContainer CreateFooterContent() => new TestFooterContent();
public partial class TestFooterContent : VisibilityContainer
{
[BackgroundDependencyLoader]
private void load()
{
AutoSizeAxes = Axes.Both;
InternalChild = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Children = new[]
{
new ShearedButton(200) { Text = "Action #1", Action = () => { } },
new ShearedButton(140) { Text = "Action #2", Action = () => { } },
}
};
}
protected override void PopIn()
{
this.MoveToY(0, 400, Easing.OutQuint)
.FadeIn(400, Easing.OutQuint);
}
protected override void PopOut()
{
this.MoveToY(-20f, 200, Easing.OutQuint)
.FadeOut(200, Easing.OutQuint);
}
}
}
}
}
@@ -48,15 +48,16 @@ using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Screens.Play.PlayerSettings;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps.IO;
using osu.Game.Tests.Resources;
using osu.Game.Utils;
using osuTK;
using osuTK.Input;
using CollectionDropdown = osu.Game.Screens.Select.CollectionDropdown;
namespace osu.Game.Tests.Visual.Navigation
{
@@ -94,7 +95,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("edit playlist", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelectV2 songSelect && songSelect.IsLoaded && !songSelect.IsFiltering);
AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelect songSelect && songSelect.IsLoaded && !songSelect.IsFiltering);
AddUntilStep("wait for selection", () => !Game.Beatmap.IsDefault);
@@ -109,7 +110,7 @@ namespace osu.Game.Tests.Visual.Navigation
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelectV2 songSelect && songSelect.IsLoaded && !songSelect.IsFiltering);
AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelect songSelect && songSelect.IsLoaded && !songSelect.IsFiltering);
AddStep("press home button", () =>
{
@@ -197,14 +198,14 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("set filter again", () => filterControlTextBox().Current.Value = "test");
AddStep("open collections dropdown", () =>
{
InputManager.MoveMouseTo(songSelect.ChildrenOfType<Screens.SelectV2.CollectionDropdown>().Single());
InputManager.MoveMouseTo(songSelect.ChildrenOfType<CollectionDropdown>().Single());
InputManager.Click(MouseButton.Left);
});
AddStep("press back once", () => InputManager.Click(MouseButton.Button1));
AddAssert("still at song select", () => Game.ScreenStack.CurrentScreen == songSelect);
AddAssert("collections dropdown closed", () => songSelect
.ChildrenOfType<Screens.SelectV2.CollectionDropdown>().Single()
.ChildrenOfType<CollectionDropdown>().Single()
.ChildrenOfType<Dropdown<CollectionFilterMenuItem>.DropdownMenu>().Single().State == MenuState.Closed);
AddStep("press back a second time", () => InputManager.Click(MouseButton.Button1));
@@ -317,7 +318,7 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestAttemptPlayBeatmapWrongHashFails()
{
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely());
PushAndConfirm(() => songSelect = new SoloSongSelect());
@@ -352,7 +353,7 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestAttemptPlayBeatmapMissingFails()
{
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely());
PushAndConfirm(() => songSelect = new SoloSongSelect());
@@ -386,7 +387,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
Player player = null;
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented);
@@ -429,7 +430,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
Player player = null;
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented);
@@ -483,7 +484,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
Player player = null;
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented);
@@ -526,7 +527,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
Player player = null;
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented);
@@ -1194,9 +1195,9 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("close settings sidebar", () => InputManager.Key(Key.Escape));
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
AddRepeatStep("go to solo", () => InputManager.Key(Key.P), 3);
AddUntilStep("wait for song select", () => (songSelect = Game.ScreenStack.CurrentScreen as Screens.SelectV2.SongSelect) != null);
AddUntilStep("wait for song select", () => (songSelect = Game.ScreenStack.CurrentScreen as Screens.Select.SongSelect) != null);
AddUntilStep("wait for beatmap sets loaded", () => songSelect.CarouselItemsPresented);
AddStep("switch to osu! ruleset", () =>
@@ -1281,7 +1282,7 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestExitSongSelectAndImmediatelyClickLogo()
{
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented);
@@ -1312,7 +1313,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
BeatmapSetInfo beatmap = null;
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented);
@@ -1371,7 +1372,7 @@ namespace osu.Game.Tests.Visual.Navigation
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
Screens.SelectV2.SongSelect songSelect = null;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented);
@@ -27,7 +27,7 @@ using osu.Game.Screens.Edit.Components;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Play.HUD.HitErrorMeters;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Skinning;
using osu.Game.Tests.Beatmaps.IO;
using osuTK;
@@ -24,17 +24,13 @@ using osu.Game.Screens.Footer;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps.IO;
using osu.Game.Tests.Resources;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Navigation
{
/// <summary>
/// Tests copied out of `TestSceneScreenNavigation` which are specific to song select.
/// These are for SongSelectV2. Eventually, the tests in the above class should be deleted along with old song select.
/// </summary>
public partial class TestSceneSongSelectNavigation : OsuGameTestScene
{
[Test]
@@ -277,7 +273,7 @@ namespace osu.Game.Tests.Visual.Navigation
/// <summary>
/// Note: This test was written to demonstrate the failure described at https://github.com/ppy/osu/issues/35023,
/// but because the failure scenario there entailed a race condition, it was possible for the test to pass regardless
/// unless <see cref="osu.Game.Screens.SelectV2.SongSelect.SELECTION_DEBOUNCE"/> was increased.
/// unless <see cref="osu.Game.Screens.Select.SongSelect.SELECTION_DEBOUNCE"/> was increased.
/// </summary>
[Test]
public void TestPresentFromResults()
@@ -12,15 +12,15 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Localisation;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Select.Details;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.SongSelect
namespace osu.Game.Tests.Visual.Online
{
[System.ComponentModel.Description("Advanced beatmap statistics display")]
public partial class TestSceneAdvancedStats : OsuTestScene
@@ -22,7 +22,6 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Select.Details;
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
namespace osu.Game.Tests.Visual.Online
@@ -72,6 +71,10 @@ namespace osu.Game.Tests.Visual.Online
Preview = @"https://b.ppy.sh/preview/12345.mp3",
PlayCount = 123,
FavouriteCount = 456,
NominationStatus = new BeatmapSetNominationStatus
{
Current = 2,
},
Submitted = DateTime.Now,
Ranked = DateTime.Now,
BPM = 111,
@@ -12,7 +12,6 @@ using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Screens.Select.Details;
namespace osu.Game.Tests.Visual.Online
{
@@ -16,7 +16,6 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Screens.Select.Details;
using osuTK;
using osuTK.Graphics;
@@ -4,9 +4,9 @@
using osu.Game.Overlays.BeatmapSet;
using osu.Framework.Graphics;
using osu.Framework.Bindables;
using osu.Game.Screens.Select.Leaderboards;
using osu.Framework.Allocation;
using osu.Game.Overlays;
using osu.Game.Screens.Play.Leaderboards;
namespace osu.Game.Tests.Visual.Online
{
@@ -17,13 +17,13 @@ namespace osu.Game.Tests.Visual.Playlists
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
private readonly FooterButtonFreeModsV2 button;
private readonly FooterButtonFreeMods button;
public TestSceneFooterButtonFreeModsV2()
{
ModSelectOverlay modSelectOverlay;
Add(modSelectOverlay = new TestModSelectOverlay());
Add(button = new FooterButtonFreeModsV2(modSelectOverlay)
Add(button = new FooterButtonFreeMods(modSelectOverlay)
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
@@ -15,7 +15,7 @@ namespace osu.Game.Tests.Visual.Playlists
public TestSceneFooterButtonFreestyleV2()
{
Add(new FooterButtonFreestyleV2
Add(new FooterButtonFreestyle
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
@@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Playlists
{
base.SetUpSteps();
AddStep("add tray", () => Child = new PlaylistsSongSelectV2.PlaylistTray(room = new Room())
AddStep("add tray", () => Child = new PlaylistsSongSelect.PlaylistTray(room = new Room())
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
@@ -13,11 +13,11 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
@@ -34,6 +34,7 @@ using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.OnlinePlay;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Playlists
{
@@ -215,6 +216,85 @@ namespace osu.Game.Tests.Visual.Playlists
AddUntilStep("second beatmap selected", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0]));
}
[Test]
public void TestFreestyleSelectAbort()
{
Room room = null!;
AddStep("add room", () =>
{
room = new Room
{
RoomID = 1,
Playlist =
[
new PlaylistItem(importedSet.Beatmaps[0])
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
Freestyle = true
},
]
};
API.Perform(new CreateRoomRequest(room));
});
TestPlaylistsScreen playlistsScreen = null!;
AddStep("load screen", () => LoadScreen(playlistsScreen = new TestPlaylistsScreen(new TestPlaylistsRoomSubScreen(room))));
AddUntilStep("wait for playlist room screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomSubScreen roomSubScreen && roomSubScreen.IsLoaded);
AddUntilStep("original beatmap", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0]));
AddStep("enter freestyle select", () => playlistsScreen.Stack.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistEditButton>().Single(b => b.IsPresent).TriggerClick());
AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelect selectScreen && selectScreen.CarouselItemsPresented);
AddStep("select next beatmap", () => InputManager.Key(Key.Down));
AddStep("abort", () => playlistsScreen.Stack.CurrentScreen.Exit());
AddUntilStep("beatmap not changed", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0]));
}
[Test]
public void TestFreestyleSelect()
{
Room room = null!;
AddStep("add room", () =>
{
room = new Room
{
RoomID = 1,
Playlist =
[
new PlaylistItem(importedSet.Beatmaps[0])
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
Freestyle = true
},
]
};
API.Perform(new CreateRoomRequest(room));
});
TestPlaylistsScreen playlistsScreen = null!;
AddStep("load screen", () => LoadScreen(playlistsScreen = new TestPlaylistsScreen(new TestPlaylistsRoomSubScreen(room))));
AddUntilStep("wait for playlist room screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomSubScreen roomSubScreen && roomSubScreen.IsLoaded);
AddUntilStep("original beatmap", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0]));
AddStep("enter freestyle select", () => playlistsScreen.Stack.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistEditButton>().Single(b => b.IsPresent).TriggerClick());
AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelect selectScreen && selectScreen.CarouselItemsPresented);
AddStep("select next beatmap", () => InputManager.Key(Key.Down));
AddStep("select (beatmap)", () => InputManager.Key(Key.Enter));
AddStep("select (exit screen)", () => InputManager.Key(Key.Enter));
AddUntilStep("beatmap changed", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[1]));
}
/// <summary>
/// Tests that the ruleset style is reset when the selected item is changed and it's no longer valid.
/// </summary>
@@ -591,30 +671,16 @@ namespace osu.Game.Tests.Visual.Playlists
private partial class TestPlaylistsScreen : OsuScreen
{
public readonly OnlinePlaySubScreenStack Stack;
public TestPlaylistsScreen(PlaylistsRoomSubScreen screen)
{
OnlinePlaySubScreenStack stack;
InternalChildren = new Drawable[]
InternalChild = Stack = new OnlinePlaySubScreenStack
{
stack = new OnlinePlaySubScreenStack
{
RelativeSizeAxes = Axes.Both
},
new BackButton
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
State = { Value = Visibility.Visible },
Action = () =>
{
if (stack.CurrentScreen is not PlaylistsRoomSubScreen)
stack.Exit();
}
}
RelativeSizeAxes = Axes.Both
};
stack.Push(screen);
Stack.Push(screen);
}
}
@@ -19,8 +19,8 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.Ranking
@@ -14,10 +14,9 @@ using osu.Game.Graphics.Carousel;
using osu.Game.Scoring;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class BeatmapCarouselFilterGroupingTest
@@ -12,10 +12,9 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics.Carousel;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class BeatmapCarouselFilterSortingTest
@@ -25,15 +25,13 @@ using osu.Game.Overlays;
using osu.Game.Scoring;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Resources;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public abstract partial class BeatmapCarouselTestScene : OsuManualInputManagerTestScene
{
@@ -9,7 +9,7 @@ using osu.Framework.Testing;
using osu.Game.Graphics.Cursor;
using osu.Game.Overlays;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public abstract partial class SongSelectComponentsTestScene : OsuManualInputManagerTestScene
{
@@ -23,11 +23,11 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public abstract partial class SongSelectTestScene : ScreenTestScene
{
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
private RealmDetachedBeatmapStore beatmapStore = null!;
protected Screens.SelectV2.SongSelect SongSelect { get; private set; } = null!;
protected Screens.Select.SongSelect SongSelect { get; private set; } = null!;
protected BeatmapCarousel Carousel => SongSelect.ChildrenOfType<BeatmapCarousel>().Single();
[Cached]
File diff suppressed because it is too large Load Diff
@@ -7,12 +7,12 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.Carousel;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselArtistGrouping : BeatmapCarouselTestScene
@@ -8,7 +8,7 @@ using osu.Framework.Testing;
using osu.Game.Collections;
using osu.Game.Screens.Select.Filter;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselCollectionGrouping : BeatmapCarouselTestScene
@@ -5,11 +5,11 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Graphics.Carousel;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselDifficultyGrouping : BeatmapCarouselTestScene
@@ -9,11 +9,11 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselFiltering : BeatmapCarouselTestScene
@@ -4,12 +4,12 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselNoGrouping : BeatmapCarouselTestScene
@@ -5,10 +5,10 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselRandom : BeatmapCarouselTestScene
@@ -5,9 +5,9 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Testing;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselScrolling : BeatmapCarouselTestScene
@@ -6,10 +6,10 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselSetsSplitApart : BeatmapCarouselTestScene
@@ -12,11 +12,11 @@ using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselUpdateHandling : BeatmapCarouselTestScene
@@ -1,162 +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.
#nullable disable
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect
{
[System.ComponentModel.Description("PlaySongSelect beatmap details")]
public partial class TestSceneBeatmapDetails : OsuTestScene
{
private BeatmapDetails details;
private DummyAPIAccess api => (DummyAPIAccess)API;
[SetUp]
public void Setup() => Schedule(() =>
{
Child = details = new BeatmapDetails
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(150),
};
});
[Test]
public void TestAllMetrics()
{
AddStep("all metrics", () => details.BeatmapInfo = new APIBeatmap
{
BeatmapSet = new APIBeatmapSet
{
Source = "osu!",
Tags = "this beatmap has all the metrics",
Ratings = Enumerable.Range(0, 11).ToArray(),
},
DifficultyName = "All Metrics",
CircleSize = 7,
DrainRate = 1,
OverallDifficulty = 5.7f,
ApproachRate = 3.5f,
StarRating = 5.3f,
FailTimes = new APIFailTimes
{
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
});
}
[Test]
public void TestAllMetricsExceptSource()
{
AddStep("all except source", () => details.BeatmapInfo = new APIBeatmap
{
BeatmapSet = new APIBeatmapSet
{
Tags = "this beatmap has all the metrics",
Ratings = Enumerable.Range(0, 11).ToArray(),
},
DifficultyName = "All Metrics",
CircleSize = 7,
DrainRate = 1,
OverallDifficulty = 5.7f,
ApproachRate = 3.5f,
StarRating = 5.3f,
FailTimes = new APIFailTimes
{
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
});
}
[Test]
public void TestOnlyRatings()
{
AddStep("ratings", () => details.BeatmapInfo = new APIBeatmap
{
BeatmapSet = new APIBeatmapSet
{
Ratings = Enumerable.Range(0, 11).ToArray(),
Source = "osu!",
Tags = "this beatmap has ratings metrics but not retries or fails",
},
DifficultyName = "Only Ratings",
CircleSize = 6,
DrainRate = 9,
OverallDifficulty = 6,
ApproachRate = 6,
StarRating = 4.8f,
});
}
[Test]
public void TestOnlyFailsAndRetries()
{
AddStep("fails retries", () => details.BeatmapInfo = new APIBeatmap
{
DifficultyName = "Only Retries and Fails",
BeatmapSet = new APIBeatmapSet
{
Source = "osu!",
Tags = "this beatmap has retries and fails but no ratings",
},
CircleSize = 3.7f,
DrainRate = 6,
OverallDifficulty = 6,
ApproachRate = 7,
StarRating = 2.91f,
FailTimes = new APIFailTimes
{
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
});
}
[Test]
public void TestNoMetrics()
{
AddStep("no metrics", () => details.BeatmapInfo = new APIBeatmap
{
DifficultyName = "No Metrics",
BeatmapSet = new APIBeatmapSet
{
Source = "osu!",
Tags = "this beatmap has no metrics",
},
CircleSize = 5,
DrainRate = 5,
OverallDifficulty = 5.5f,
ApproachRate = 6.5f,
StarRating = 1.97f,
});
}
[Test]
public void TestNullBeatmap()
{
AddStep("null beatmap", () => details.BeatmapInfo = null);
}
[Test]
public void TestOnlineMetrics()
{
AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new APIBeatmap
{
OnlineID = 162,
});
AddStep("set online", () => api.SetState(APIState.Online));
AddStep("set offline", () => api.SetState(APIState.Offline));
}
}
}
@@ -4,9 +4,9 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneBeatmapFilterControl : SongSelectComponentsTestScene
{
@@ -1,305 +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.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Extensions;
using osu.Game.Graphics.Sprites;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko;
using osu.Game.Screens.Select;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapInfoWedge : OsuTestScene
{
[Resolved]
private RulesetStore rulesets { get; set; } = null!;
private TestBeatmapInfoWedge infoWedge = null!;
private readonly List<IBeatmap> beatmaps = new List<IBeatmap>();
protected override void LoadComplete()
{
base.LoadComplete();
Add(infoWedge = new TestBeatmapInfoWedge
{
Size = new Vector2(0.5f, 245),
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Top = 20 }
});
AddStep("show", () => infoWedge.Show());
selectBeatmap(Beatmap.Value.Beatmap);
AddWaitStep("wait for select", 3);
AddStep("hide", () => { infoWedge.Hide(); });
AddWaitStep("wait for hide", 3);
AddStep("show", () => { infoWedge.Show(); });
AddSliderStep("change star difficulty", 0, 11.9, 5.55, v =>
{
foreach (var hasCurrentValue in infoWedge.Info.ChildrenOfType<IHasCurrentValue<StarDifficulty>>())
hasCurrentValue.Current.Value = new StarDifficulty(v, 0);
});
foreach (var rulesetInfo in rulesets.AvailableRulesets)
{
var instance = rulesetInfo.CreateInstance();
var testBeatmap = CreateTestBeatmap(rulesetInfo);
beatmaps.Add(testBeatmap);
setRuleset(rulesetInfo);
selectBeatmap(testBeatmap);
testBeatmapLabels(instance);
switch (instance)
{
case OsuRuleset:
testInfoLabels(5);
break;
case TaikoRuleset:
testInfoLabels(5);
break;
case CatchRuleset:
testInfoLabels(5);
break;
case ManiaRuleset:
testInfoLabels(4);
break;
default:
testInfoLabels(2);
break;
}
}
}
private void testBeatmapLabels(Ruleset ruleset)
{
AddAssert("check version", () => infoWedge.Info.VersionLabel.Current.Value == $"{ruleset.ShortName}Version");
AddAssert("check title", () => infoWedge.Info.TitleLabel.Current.Value == $"{ruleset.ShortName}Title");
AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Current.Value == $"{ruleset.ShortName}Artist");
AddAssert("check author", () => infoWedge.Info.MapperContainer.ChildrenOfType<OsuSpriteText>().Any(s => s.Current.Value == $"{ruleset.ShortName}Author"));
}
private void testInfoLabels(int expectedCount)
{
AddAssert("check info labels exists", () => infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Any());
AddAssert("check info labels count", () => infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Count() == expectedCount);
}
[SetUpSteps]
public void SetUpSteps()
{
AddStep("reset mods", () => SelectedMods.SetDefault());
}
[Test]
public void TestTruncation()
{
selectBeatmap(CreateLongMetadata());
}
[Test]
public void TestNullBeatmap()
{
selectBeatmap(null);
AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Current.Value));
AddAssert("check default title", () => infoWedge.Info.TitleLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Title);
AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Artist);
AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.ChildrenOfType<OsuSpriteText>().Any());
AddAssert("check no info labels", () => !infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Any());
}
[Test]
public void TestBPMUpdates()
{
const double bpm = 120;
IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo);
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm });
OsuModDoubleTime doubleTime = null!;
selectBeatmap(beatmap);
checkDisplayedBPM($"{bpm}");
AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() });
checkDisplayedBPM($"{bpm * 1.5f}");
AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2);
checkDisplayedBPM($"{bpm * 2}");
}
[TestCase(120, 125, null, "120-125 (mostly 120)")]
[TestCase(120, 120.6, null, "120-121 (mostly 120)")]
[TestCase(120, 120.4, null, "120")]
[TestCase(120, 120.6, "DT", "180-181 (mostly 180)")]
[TestCase(120, 120.4, "DT", "180-181 (mostly 180)")]
public void TestVaryingBPM(double commonBpm, double otherBpm, string? mod, string expectedDisplay)
{
IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo);
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm });
beatmap.ControlPointInfo.Add(100, new TimingControlPoint { BeatLength = 60 * 1000 / otherBpm });
beatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm });
if (mod != null)
AddStep($"select {mod}", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateModFromAcronym(mod) });
selectBeatmap(beatmap);
checkDisplayedBPM(expectedDisplay);
}
private void checkDisplayedBPM(string target)
{
AddUntilStep($"displayed bpm is {target}", () =>
{
var label = infoWedge.DisplayedContent.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Single(l => l.Statistic.Name == BeatmapsetsStrings.ShowStatsBpm);
return label.Statistic.Content == target;
});
}
[TestCase]
public void TestLengthUpdates()
{
IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo);
double drain = beatmap.CalculateDrainLength();
beatmap.BeatmapInfo.Length = drain;
OsuModDoubleTime doubleTime = null!;
selectBeatmap(beatmap);
checkDisplayedLength(drain);
AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() });
checkDisplayedLength(Math.Round(drain / 1.5f));
AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2);
checkDisplayedLength(Math.Round(drain / 2));
}
private void checkDisplayedLength(double drain)
{
var displayedLength = drain.ToFormattedDuration();
AddUntilStep($"check map drain ({displayedLength})", () =>
{
var label = infoWedge.DisplayedContent.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>()
.Single(l => l.Statistic.Name == BeatmapsetsStrings.ShowStatsTotalLength(displayedLength));
return label.Statistic.Content == displayedLength.ToString();
});
}
private void setRuleset(RulesetInfo rulesetInfo)
{
Container? containerBefore = null;
AddStep("set ruleset", () =>
{
// wedge content is only refreshed if the ruleset changes, so only wait for load in that case.
if (!rulesetInfo.Equals(Ruleset.Value))
containerBefore = infoWedge.DisplayedContent;
Ruleset.Value = rulesetInfo;
});
AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore);
}
private void selectBeatmap(IBeatmap? b)
{
Container? containerBefore = null;
AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () =>
{
containerBefore = infoWedge.DisplayedContent;
infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : CreateWorkingBeatmap(b);
});
AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore);
}
public static IBeatmap CreateTestBeatmap(RulesetInfo ruleset)
{
List<HitObject> objects = new List<HitObject>();
for (double i = 0; i < 50000; i += 1000)
objects.Add(new TestHitObject { StartTime = i });
return new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Author = { Username = $"{ruleset.ShortName}Author" },
Artist = $"{ruleset.ShortName}Artist",
Source = $"{ruleset.ShortName}Source",
Title = $"{ruleset.ShortName}Title"
},
Ruleset = ruleset,
StarRating = 6,
DifficultyName = $"{ruleset.ShortName}Version",
Difficulty = new BeatmapDifficulty()
},
HitObjects = objects
};
}
public static IBeatmap CreateLongMetadata()
{
return new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Author = { Username = "WWWWWWWWWWWWWWW" },
Artist = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Artist",
Source = "Verrrrry long Source",
Title = "Verrrrry long Title"
},
DifficultyName = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version",
Status = BeatmapOnlineStatus.Graveyard,
},
};
}
private partial class TestBeatmapInfoWedge : BeatmapInfoWedge
{
public new Container DisplayedContent => base.DisplayedContent;
public new WedgeInfoText Info => base.Info;
}
private class TestHitObject : ConvertHitObject;
}
}
@@ -21,13 +21,13 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Users;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneBeatmapLeaderboardScore : SongSelectComponentsTestScene
{
@@ -24,11 +24,11 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneBeatmapLeaderboardSorting : SongSelectComponentsTestScene
{
@@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
private LeaderboardManager leaderboardManager = null!;
private readonly IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
private readonly IBindable<Screens.Select.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.Select.SongSelect.BeatmapSetLookupResult?>();
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
@@ -25,13 +25,13 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Users;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneBeatmapLeaderboardWedge : SongSelectComponentsTestScene
{
@@ -13,16 +13,16 @@ using osu.Game.Extensions;
using osu.Game.Graphics.Sprites;
using osu.Game.Models;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneBeatmapMetadataWedge : SongSelectComponentsTestScene
{
private BeatmapMetadataWedge wedge = null!;
[Cached(typeof(IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
[Cached(typeof(IBindable<Screens.Select.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.Select.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.Select.SongSelect.BeatmapSetLookupResult?>();
protected override void LoadComplete()
{
@@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapInfo.OnlineID = 0;
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null);
onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null);
});
}
@@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
var (working, _) = createTestBeatmap();
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null);
onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null);
});
AddAssert("rating wedge still hidden", () => !wedge.RatingsVisible);
AddAssert("fail time wedge still hidden", () => !wedge.FailRetryVisible);
@@ -189,7 +189,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
var (working, online) = createTestBeatmap();
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
});
AddWaitStep("wait", 5);
@@ -203,7 +203,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
online.Result!.RelatedTags[2].Name = "some/tag";
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
});
AddWaitStep("wait", 5);
@@ -217,7 +217,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
});
AddWaitStep("wait", 5);
@@ -231,13 +231,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
});
AddWaitStep("wait", 5);
}
private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
private (WorkingBeatmap, Screens.Select.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
{
var working = CreateWorkingBeatmap(Ruleset.Value);
var onlineSet = new APIBeatmapSet
@@ -292,7 +292,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now;
working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now;
working.Metadata.UserTags.AddRange(onlineSet.RelatedTags.Select(t => t.Name));
return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
return (working, Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
}
}
}
@@ -1,31 +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.ComponentModel;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Screens.Select.Options;
namespace osu.Game.Tests.Visual.SongSelect
{
[Description("bottom beatmap details")]
public partial class TestSceneBeatmapOptionsOverlay : OsuTestScene
{
public TestSceneBeatmapOptionsOverlay()
{
var overlay = new BeatmapOptionsOverlay();
var colours = new OsuColour();
overlay.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, null);
overlay.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, null);
overlay.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null);
overlay.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, null);
overlay.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, null);
Add(overlay);
AddStep(@"Toggle", overlay.ToggleVisibility);
}
}
}
@@ -23,7 +23,7 @@ using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Users;
using osu.Game.Utils;
@@ -29,11 +29,10 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Skinning;
using osu.Game.Tests.Visual.SongSelect;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneBeatmapTitleWedge : SongSelectComponentsTestScene
{
@@ -42,8 +41,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
private BeatmapTitleWedge titleWedge = null!;
private BeatmapTitleWedge.DifficultyDisplay difficultyDisplay => titleWedge.ChildrenOfType<BeatmapTitleWedge.DifficultyDisplay>().Single();
[Cached(typeof(IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
[Cached(typeof(IBindable<Screens.Select.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.Select.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.Select.SongSelect.BeatmapSetLookupResult?>();
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
@@ -86,7 +85,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
foreach (var rulesetInfo in rulesets.AvailableRulesets)
{
var testBeatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(rulesetInfo);
var testBeatmap = createTestBeatmapFromRuleset(rulesetInfo);
setRuleset(rulesetInfo);
selectBeatmap(testBeatmap);
@@ -108,7 +107,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
public void TestBPMUpdates()
{
const double bpm = 120;
IBeatmap beatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(new OsuRuleset().RulesetInfo);
IBeatmap beatmap = createTestBeatmapFromRuleset(new OsuRuleset().RulesetInfo);
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm });
OsuModDoubleTime doubleTime = null!;
@@ -160,7 +159,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
var (working, _) = createTestBeatmap();
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null);
onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null);
});
AddUntilStep("play count is -", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("-"));
AddUntilStep("favourites count is -", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("-"));
@@ -255,7 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[TestCase(120, 120.4, "DT", "180-181 (mostly 180)")]
public void TestVaryingBPM(double commonBpm, double otherBpm, string? mod, string expectedDisplay)
{
IBeatmap beatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(new OsuRuleset().RulesetInfo);
IBeatmap beatmap = createTestBeatmapFromRuleset(new OsuRuleset().RulesetInfo);
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm });
beatmap.ControlPointInfo.Add(100, new TimingControlPoint { BeatLength = 60 * 1000 / otherBpm });
beatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm });
@@ -299,7 +298,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
});
}
private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
private (WorkingBeatmap, Screens.Select.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
{
var working = CreateWorkingBeatmap(Ruleset.Value);
var onlineSet = new APIBeatmapSet
@@ -320,7 +319,33 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now;
working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now;
return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
return (working, Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
}
private static IBeatmap createTestBeatmapFromRuleset(RulesetInfo ruleset)
{
List<HitObject> objects = new List<HitObject>();
for (double i = 0; i < 50000; i += 1000)
objects.Add(new TestHitObject { StartTime = i });
return new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Author = { Username = $"{ruleset.ShortName}Author" },
Artist = $"{ruleset.ShortName}Artist",
Source = $"{ruleset.ShortName}Source",
Title = $"{ruleset.ShortName}Title"
},
Ruleset = ruleset,
StarRating = 6,
DifficultyName = $"{ruleset.ShortName}Version",
Difficulty = new BeatmapDifficulty()
},
HitObjects = objects
};
}
private class TestHitObject : ConvertHitObject;
@@ -8,10 +8,10 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Visual.UserInterface;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneBeatmapTitleWedgeStatistic : ThemeComparisonTestScene
{
@@ -24,9 +24,13 @@ using osu.Game.Rulesets;
using osu.Game.Tests.Resources;
using osuTK.Input;
using Realms;
using CollectionDropdown = osu.Game.Screens.Select.CollectionDropdown;
namespace osu.Game.Tests.Visual.SongSelect
{
/// <summary>
/// WARNING: TODO: we have TWO `CollectionDropdowns` with diverging functionality. This is not good.
/// </summary>
public partial class TestSceneCollectionDropdown : OsuManualInputManagerTestScene
{
private RulesetStore rulesets = null!;
@@ -198,8 +202,6 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestManageCollectionsFilterIsNotSelected()
{
bool received = false;
addExpandHeaderStep();
AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1", new List<string> { "abc" }))));
@@ -213,12 +215,6 @@ namespace osu.Game.Tests.Visual.SongSelect
addExpandHeaderStep();
AddStep("watch for filter requests", () =>
{
received = false;
dropdown.ChildrenOfType<CollectionDropdown>().First().RequestFilter = () => received = true;
});
AddStep("click manage collections filter", () =>
{
int lastItemIndex = dropdown.ChildrenOfType<CollectionDropdown>().Single().Items.Count() - 1;
@@ -227,8 +223,6 @@ namespace osu.Game.Tests.Visual.SongSelect
});
AddAssert("collection filter still selected", () => dropdown.Current.Value.CollectionName == "1");
AddAssert("filter request not fired", () => !received);
}
private void writeAndRefresh(Action<Realm> action) => Realm.Write(r =>
@@ -241,7 +235,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void assertCollectionHeaderDisplays(LocalisableString collectionName, bool shouldDisplay = true)
=> AddUntilStep($"collection dropdown header displays '{collectionName}'",
() => shouldDisplay == dropdown.ChildrenOfType<CollectionDropdown.OsuDropdownHeader>().Any(h => h.ChildrenOfType<SpriteText>().Any(t => t.Text == collectionName)));
() => shouldDisplay == dropdown.ChildrenOfType<CollectionDropdown.ShearedDropdownHeader>().Any(h => h.ChildrenOfType<SpriteText>().Any(t => t.Text == collectionName)));
private void assertFirstButtonIs(IconUsage icon) => AddUntilStep($"button is {icon.Icon.ToString()}", () => getAddOrRemoveButton(1).Icon.Equals(icon));
@@ -255,7 +249,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void addExpandHeaderStep() => AddStep("expand header", () =>
{
InputManager.MoveMouseTo(dropdown.ChildrenOfType<CollectionDropdown.OsuDropdownHeader>().Single());
InputManager.MoveMouseTo(dropdown.ChildrenOfType<CollectionDropdown.ShearedDropdownHeader>().Single());
InputManager.Click(MouseButton.Left);
});
@@ -7,12 +7,12 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Overlays;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Visual.UserInterface;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneDifficultyRangeSlider : ThemeComparisonTestScene
{
@@ -11,10 +11,10 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Game.Overlays;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneDifficultyStatisticsDisplay : OsuTestScene
{
@@ -1,24 +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 NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneFilterControl : OsuManualInputManagerTestScene
{
[SetUp]
public void SetUp() => Schedule(() =>
{
Child = new FilterControl
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Height = FilterControl.HEIGHT,
};
});
}
}
@@ -13,10 +13,10 @@ using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Utils;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneFooterButtonMods : OsuTestScene
{
@@ -19,12 +19,12 @@ using osu.Game.Overlays;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.UserInterface;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestScenePanelBeatmap : ThemeComparisonTestScene
{
@@ -19,12 +19,12 @@ using osu.Game.Overlays;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.UserInterface;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestScenePanelBeatmapStandalone : ThemeComparisonTestScene
{
@@ -7,15 +7,15 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Graphics.Carousel;
using osu.Game.Graphics.Cursor;
using osu.Game.Overlays;
using osu.Game.Scoring;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Visual.UserInterface;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestScenePanelGroup : ThemeComparisonTestScene
{
@@ -11,12 +11,12 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics.Carousel;
using osu.Game.Graphics.Cursor;
using osu.Game.Overlays;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.UserInterface;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestScenePanelSet : ThemeComparisonTestScene
{
@@ -5,9 +5,9 @@ using System;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Screens.SelectV2;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestScenePanelUpdateBeatmapButton : OsuTestScene
{
@@ -20,18 +20,17 @@ using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.Leaderboards;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
using osuTK.Input;
using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel;
using FooterButtonMods = osu.Game.Screens.SelectV2.FooterButtonMods;
using FooterButtonOptions = osu.Game.Screens.SelectV2.FooterButtonOptions;
using FooterButtonRandom = osu.Game.Screens.SelectV2.FooterButtonRandom;
using BeatmapCarousel = osu.Game.Screens.Select.BeatmapCarousel;
using FooterButtonMods = osu.Game.Screens.Select.FooterButtonMods;
using FooterButtonOptions = osu.Game.Screens.Select.FooterButtonOptions;
using FooterButtonRandom = osu.Game.Screens.Select.FooterButtonRandom;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneSongSelect : SongSelectTestScene
{
@@ -324,7 +323,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddStep("exit gameplay", () => Stack.CurrentScreen.Exit());
AddUntilStep("wait for song select", () => Stack.CurrentScreen is Screens.SelectV2.SongSelect);
AddUntilStep("wait for song select", () => Stack.CurrentScreen is Screens.Select.SongSelect);
AddUntilStep("wait for filtered", () => SongSelect.ChildrenOfType<BeatmapCarousel>().Single().FilterCount, () => Is.EqualTo(2));
}
@@ -8,11 +8,11 @@ using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
/// <summary>
/// The fallback behaviour guaranteed by SongSelect is that a random selection will happen in worst case scenario.
@@ -226,7 +226,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
Beatmaps.Delete(Beatmaps.GetAllUsableBeatmapSets().Last());
// check selection during debounce
Scheduler.AddDelayed(() => selectedBeatmapDuringDebounce = Beatmap.Value.BeatmapInfo, Screens.SelectV2.SongSelect.SELECTION_DEBOUNCE / 2f);
Scheduler.AddDelayed(() => selectedBeatmapDuringDebounce = Beatmap.Value.BeatmapInfo, Screens.Select.SongSelect.SELECTION_DEBOUNCE / 2f);
});
WaitForFiltering();
@@ -12,16 +12,17 @@ using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Chat;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osuTK.Input;
using FilterControl = osu.Game.Screens.SelectV2.FilterControl;
using NoResultsPlaceholder = osu.Game.Screens.SelectV2.NoResultsPlaceholder;
using FilterControl = osu.Game.Screens.Select.FilterControl;
using NoResultsPlaceholder = osu.Game.Screens.Select.NoResultsPlaceholder;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneSongSelectFiltering : SongSelectTestScene
{
@@ -266,6 +267,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible);
AddAssert("still has selection", () => Beatmap.IsDefault, () => Is.False);
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMinimum, 0.0));
}
[Test]
@@ -365,13 +368,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
SortBy(SortMode.Difficulty);
checkMatchedBeatmaps(6);
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Any(d => d.Enabled.Value));
AddStep("click spread indicator", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Single(d => d.Enabled.Value));
InputManager.Click(MouseButton.Left);
});
WaitForFiltering();
scopeBeatmap(false);
checkMatchedBeatmaps(3);
AddStep("press Escape", () => InputManager.Key(Key.Escape));
@@ -389,9 +386,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
SortBy(SortMode.Artist);
checkMatchedBeatmaps(6);
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Any(d => d.Enabled.Value));
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
WaitForFiltering();
scopeBeatmap(true);
checkMatchedBeatmaps(3);
AddStep("press Escape", () => InputManager.Key(Key.Escape));
@@ -413,9 +408,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
WaitForFiltering();
checkMatchedBeatmaps(3);
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Any(d => d.Enabled.Value));
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
WaitForFiltering();
scopeBeatmap(true);
checkMatchedBeatmaps(3);
AddStep("press Escape", () => InputManager.Key(Key.Escape));
@@ -424,6 +417,179 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddAssert("text filter not emptied", () => filterTextBox.Current.Value, () => Is.Not.Empty);
}
[TestCase(false)]
[TestCase(true)]
public void TestUnscopeRevertsToOriginalSelection(bool grouped)
{
ImportBeatmapForRuleset(0);
ImportBeatmapForRuleset(0);
LoadSongSelect();
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
checkMatchedBeatmaps(6);
AddStep("select normal difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Normal")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal")));
scopeBeatmap(grouped);
checkMatchedBeatmaps(3);
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
AddStep("exit scoped view", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<FilterControl.ScopedBeatmapSetDisplay>().First());
InputManager.Click(MouseButton.Left);
});
WaitForFiltering();
checkMatchedBeatmaps(6);
AddAssert("normal difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal")));
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1));
}
[TestCase(false)]
[TestCase(true)]
public void TestUnscopeWhenSelectedBeatmapHiddenByFilters(bool grouped)
{
ImportBeatmapForRuleset(0);
ImportBeatmapForRuleset(0);
LoadSongSelect();
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
checkMatchedBeatmaps(6);
AddStep("set star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, findBeatmap("Hard").StarRating + 0.1));
WaitForFiltering();
AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
scopeBeatmap(grouped);
checkMatchedBeatmaps(3);
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
AddStep("exit scoped view", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<FilterControl.ScopedBeatmapSetDisplay>().First());
InputManager.Click(MouseButton.Left);
});
WaitForFiltering();
AddAssert("hard difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1));
}
[TestCase(false)]
[TestCase(true)]
public void TestUnscopeByChangingRuleset(bool grouped)
{
bool showConverts = Config.Get<bool>(OsuSetting.ShowConvertedBeatmaps);
AddStep("hide converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
ImportBeatmapForRuleset(0, 2);
LoadSongSelect();
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
checkMatchedBeatmaps(2);
scopeBeatmap(grouped);
checkMatchedBeatmaps(2);
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
AddStep("change ruleset", () => Ruleset.Value = new CatchRuleset().RulesetInfo);
WaitForFiltering();
AddAssert("hard catch difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
AddStep("revert convert setting", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, showConverts));
}
[TestCase(false)]
[TestCase(true)]
public void TestUnscopeByShowingConverts(bool grouped)
{
bool showConverts = Config.Get<bool>(OsuSetting.ShowConvertedBeatmaps);
AddStep("hide converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
ImportBeatmapForRuleset(0);
ImportBeatmapForRuleset(0);
LoadSongSelect();
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
checkMatchedBeatmaps(6);
AddStep("set star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, Beatmap.Value.BeatmapSetInfo.Beatmaps.ElementAt(1).StarRating + 0.1));
WaitForFiltering();
AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
scopeBeatmap(grouped);
checkMatchedBeatmaps(3);
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
AddStep("show converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
WaitForFiltering();
AddAssert("hard difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
AddStep("revert convert setting", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, showConverts));
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1));
}
[TestCase(false)]
[TestCase(true)]
public void TestUnscopeByChangingFilterText(bool grouped)
{
ImportBeatmapForRuleset(0);
ImportBeatmapForRuleset(0);
LoadSongSelect();
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
checkMatchedBeatmaps(6);
AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard")));
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
scopeBeatmap(grouped);
checkMatchedBeatmaps(3);
AddStep("set filter text", () => filterTextBox.Current.Value = findBeatmap("Normal").DifficultyName);
WaitForFiltering();
AddAssert("normal difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal")));
}
private void scopeBeatmap(bool grouped)
{
if (grouped)
{
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Any(d => d.Enabled.Value));
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
}
else
{
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Any(d => d.Enabled.Value));
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
}
WaitForFiltering();
}
private BeatmapInfo findBeatmap(string difficultySubstring) => Beatmap.Value.BeatmapSetInfo.Beatmaps.First(b => b.DifficultyName.Contains(difficultySubstring));
private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType<NoResultsPlaceholder>().FirstOrDefault();
private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected));
@@ -1,109 +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.
#nullable disable
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Screens.Select;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneSongSelectFooter : OsuManualInputManagerTestScene
{
private FooterButtonRandom randomButton;
private bool nextRandomCalled;
private bool previousRandomCalled;
[SetUp]
public void SetUp() => Schedule(() =>
{
nextRandomCalled = false;
previousRandomCalled = false;
Footer footer;
Child = footer = new Footer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
footer.AddButton(new FooterButtonMods(), null);
footer.AddButton(randomButton = new FooterButtonRandom
{
NextRandom = () => nextRandomCalled = true,
PreviousRandom = () => previousRandomCalled = true,
}, null);
footer.AddButton(new FooterButtonOptions(), null);
InputManager.MoveMouseTo(Vector2.Zero);
});
[Test]
public void TestState()
{
AddRepeatStep("toggle options state", () => this.ChildrenOfType<FooterButton>().Last().Enabled.Toggle(), 20);
}
[Test]
public void TestFooterRandom()
{
AddStep("press F2", () => InputManager.Key(Key.F2));
AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled);
}
[Test]
public void TestFooterRandomViaMouse()
{
AddStep("click button", () =>
{
InputManager.MoveMouseTo(randomButton);
InputManager.Click(MouseButton.Left);
});
AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled);
}
[Test]
public void TestFooterRewind()
{
AddStep("press Shift+F2", () =>
{
InputManager.PressKey(Key.LShift);
InputManager.PressKey(Key.F2);
InputManager.ReleaseKey(Key.F2);
InputManager.ReleaseKey(Key.LShift);
});
AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled);
}
[Test]
public void TestFooterRewindViaShiftMouseLeft()
{
AddStep("shift + click button", () =>
{
InputManager.PressKey(Key.LShift);
InputManager.MoveMouseTo(randomButton);
InputManager.Click(MouseButton.Left);
InputManager.ReleaseKey(Key.LShift);
});
AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled);
}
[Test]
public void TestFooterRewindViaMouseRight()
{
AddStep("right click button", () =>
{
InputManager.MoveMouseTo(randomButton);
InputManager.Click(MouseButton.Right);
});
AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled);
}
}
}
@@ -16,11 +16,11 @@ using osu.Game.Models;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Scoring;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.SongSelectV2
namespace osu.Game.Tests.Visual.SongSelect
{
/// <summary>
/// Test suite for grouping modes which require the presence of API / realm.
@@ -1,224 +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.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Tests.Resources;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneTopLocalRank : OsuTestScene
{
private RulesetStore rulesets = null!;
private BeatmapManager beatmapManager = null!;
private ScoreManager scoreManager = null!;
private TopLocalRank topLocalRank = null!;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, API));
Dependencies.Cache(Realm);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
}
private BeatmapInfo importedBeatmap => beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.Ruleset.ShortName == "osu");
[SetUpSteps]
public void SetUpSteps()
{
AddStep("Delete all scores", () => scoreManager.Delete());
AddStep("Create local rank", () =>
{
Child = topLocalRank = new TopLocalRank(importedBeatmap)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Scale = new Vector2(10),
};
});
AddAssert("No rank displayed initially", () => topLocalRank.DisplayedRank == null);
}
[Test]
public void TestBasicImportDelete()
{
ScoreInfo testScoreInfo = null!;
AddStep("Add score for current user", () =>
{
testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo.User = API.LocalUser.Value;
testScoreInfo.Rank = ScoreRank.B;
scoreManager.Import(testScoreInfo);
});
AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B);
AddStep("Delete score", () => scoreManager.Delete(testScoreInfo));
AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null);
}
[Test]
public void TestRulesetChange()
{
AddStep("Add score for current user", () =>
{
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo.User = API.LocalUser.Value;
testScoreInfo.Rank = ScoreRank.B;
scoreManager.Import(testScoreInfo);
});
AddUntilStep("Wait for initial display", () => topLocalRank.DisplayedRank == ScoreRank.B);
AddStep("Change ruleset", () => Ruleset.Value = rulesets.GetRuleset("fruits"));
AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null);
AddStep("Change ruleset back", () => Ruleset.Value = rulesets.GetRuleset("osu"));
AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B);
}
[Test]
public void TestHigherScoreSet()
{
AddStep("Add score for current user", () =>
{
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo.User = API.LocalUser.Value;
testScoreInfo.Rank = ScoreRank.B;
scoreManager.Import(testScoreInfo);
});
AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B);
AddStep("Add higher score for current user", () =>
{
var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo2.User = API.LocalUser.Value;
testScoreInfo2.Rank = ScoreRank.X;
testScoreInfo2.TotalScore = 1000000;
testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics;
scoreManager.Import(testScoreInfo2);
});
AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X);
}
[Test]
public void TestLegacyScore()
{
ScoreInfo testScoreInfo = null!;
AddStep("Add legacy score for current user", () =>
{
testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo.User = API.LocalUser.Value;
testScoreInfo.Rank = ScoreRank.B;
scoreManager.Import(testScoreInfo);
});
AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B);
AddStep("Add higher-graded score for current user", () =>
{
var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo2.User = API.LocalUser.Value;
testScoreInfo2.Rank = ScoreRank.X;
testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics;
testScoreInfo2.TotalScore = testScoreInfo.TotalScore + 1;
scoreManager.Import(testScoreInfo2);
});
AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X);
}
[Test]
public void TestGuestScore()
{
AddStep("Add score for guest user", () =>
{
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo.User = new GuestUser();
testScoreInfo.Rank = ScoreRank.B;
scoreManager.Import(testScoreInfo);
});
AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.B));
}
[Test]
public void TestUnknownUserScore()
{
AddStep("Add score for unknown user", () =>
{
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo.User = new APIUser { Username = "AAA", };
testScoreInfo.Rank = ScoreRank.S;
scoreManager.Import(testScoreInfo);
});
AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.S));
}
[Test]
public void TestAnotherUserScore()
{
AddStep("Add score for not-current user", () =>
{
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
testScoreInfo.User = new APIUser { Username = "notme", Id = 43, };
testScoreInfo.Rank = ScoreRank.S;
scoreManager.Import(testScoreInfo);
});
AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank, () => Is.Null);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (rulesets.IsNotNull())
rulesets.Dispose();
}
}
}

Some files were not shown because too many files have changed in this diff Show More