diff --git a/osu.Android.props b/osu.Android.props
index 2ef3bb2dd1..584fe0a3ef 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs
index c65c9df9f9..b9d6f28228 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs
@@ -24,21 +24,24 @@ public class CatchLegacyModConversionTest : LegacyModConversionTest
new object[] { LegacyMods.DoubleTime, new[] { typeof(CatchModDoubleTime) } },
new object[] { LegacyMods.Relax, new[] { typeof(CatchModRelax) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(CatchModHalfTime) } },
- new object[] { LegacyMods.Nightcore, new[] { typeof(CatchModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(CatchModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(CatchModAutoplay) } },
- new object[] { LegacyMods.Perfect, new[] { typeof(CatchModPerfect) } },
- new object[] { LegacyMods.Cinema, new[] { typeof(CatchModCinema) } },
new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(CatchModHardRock), typeof(CatchModDoubleTime) } }
};
+ [TestCaseSource(nameof(catch_mod_mapping))]
+ [TestCase(LegacyMods.Cinema, new[] { typeof(CatchModCinema) })]
+ [TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(CatchModCinema) })]
+ [TestCase(LegacyMods.Nightcore, new[] { typeof(CatchModNightcore) })]
+ [TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(CatchModNightcore) })]
+ [TestCase(LegacyMods.Perfect, new[] { typeof(CatchModPerfect) })]
+ [TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(CatchModPerfect) })]
+ public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
+
[TestCaseSource(nameof(catch_mod_mapping))]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(CatchModCinema) })]
[TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(CatchModNightcore) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(CatchModPerfect) })]
- public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
-
- [TestCaseSource(nameof(catch_mod_mapping))]
public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new CatchRuleset();
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs
index accae29ffe..9dee861e66 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs
@@ -23,10 +23,8 @@ public class ManiaLegacyModConversionTest : LegacyModConversionTest
new object[] { LegacyMods.SuddenDeath, new[] { typeof(ManiaModSuddenDeath) } },
new object[] { LegacyMods.DoubleTime, new[] { typeof(ManiaModDoubleTime) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(ManiaModHalfTime) } },
- new object[] { LegacyMods.Nightcore, new[] { typeof(ManiaModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(ManiaModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(ManiaModAutoplay) } },
- new object[] { LegacyMods.Perfect, new[] { typeof(ManiaModPerfect) } },
new object[] { LegacyMods.Key4, new[] { typeof(ManiaModKey4) } },
new object[] { LegacyMods.Key5, new[] { typeof(ManiaModKey5) } },
new object[] { LegacyMods.Key6, new[] { typeof(ManiaModKey6) } },
@@ -34,7 +32,6 @@ public class ManiaLegacyModConversionTest : LegacyModConversionTest
new object[] { LegacyMods.Key8, new[] { typeof(ManiaModKey8) } },
new object[] { LegacyMods.FadeIn, new[] { typeof(ManiaModFadeIn) } },
new object[] { LegacyMods.Random, new[] { typeof(ManiaModRandom) } },
- new object[] { LegacyMods.Cinema, new[] { typeof(ManiaModCinema) } },
new object[] { LegacyMods.Key9, new[] { typeof(ManiaModKey9) } },
new object[] { LegacyMods.KeyCoop, new[] { typeof(ManiaModDualStages) } },
new object[] { LegacyMods.Key1, new[] { typeof(ManiaModKey1) } },
@@ -45,12 +42,18 @@ public class ManiaLegacyModConversionTest : LegacyModConversionTest
};
[TestCaseSource(nameof(mania_mod_mapping))]
+ [TestCase(LegacyMods.Cinema, new[] { typeof(ManiaModCinema) })]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(ManiaModCinema) })]
+ [TestCase(LegacyMods.Nightcore, new[] { typeof(ManiaModNightcore) })]
[TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(ManiaModNightcore) })]
+ [TestCase(LegacyMods.Perfect, new[] { typeof(ManiaModPerfect) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(ManiaModPerfect) })]
public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
[TestCaseSource(nameof(mania_mod_mapping))]
+ [TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(ManiaModCinema) })]
+ [TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(ManiaModNightcore) })]
+ [TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(ManiaModPerfect) })]
public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new ManiaRuleset();
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs
index db9872b152..01d83b55e6 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs
@@ -25,24 +25,27 @@ public class OsuLegacyModConversionTest : LegacyModConversionTest
new object[] { LegacyMods.DoubleTime, new[] { typeof(OsuModDoubleTime) } },
new object[] { LegacyMods.Relax, new[] { typeof(OsuModRelax) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(OsuModHalfTime) } },
- new object[] { LegacyMods.Nightcore, new[] { typeof(OsuModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(OsuModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(OsuModAutoplay) } },
new object[] { LegacyMods.SpunOut, new[] { typeof(OsuModSpunOut) } },
new object[] { LegacyMods.Autopilot, new[] { typeof(OsuModAutopilot) } },
- new object[] { LegacyMods.Perfect, new[] { typeof(OsuModPerfect) } },
- new object[] { LegacyMods.Cinema, new[] { typeof(OsuModCinema) } },
new object[] { LegacyMods.Target, new[] { typeof(OsuModTarget) } },
new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(OsuModHardRock), typeof(OsuModDoubleTime) } }
};
[TestCaseSource(nameof(osu_mod_mapping))]
+ [TestCase(LegacyMods.Cinema, new[] { typeof(OsuModCinema) })]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(OsuModCinema) })]
+ [TestCase(LegacyMods.Nightcore, new[] { typeof(OsuModNightcore) })]
[TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(OsuModNightcore) })]
+ [TestCase(LegacyMods.Perfect, new[] { typeof(OsuModPerfect) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(OsuModPerfect) })]
public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
[TestCaseSource(nameof(osu_mod_mapping))]
+ [TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(OsuModCinema) })]
+ [TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(OsuModNightcore) })]
+ [TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(OsuModPerfect) })]
public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new OsuRuleset();
diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoLegacyModConversionTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoLegacyModConversionTest.cs
index 3553cb27dc..c86f8cb8d2 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TaikoLegacyModConversionTest.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TaikoLegacyModConversionTest.cs
@@ -24,22 +24,25 @@ public class TaikoLegacyModConversionTest : LegacyModConversionTest
new object[] { LegacyMods.DoubleTime, new[] { typeof(TaikoModDoubleTime) } },
new object[] { LegacyMods.Relax, new[] { typeof(TaikoModRelax) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(TaikoModHalfTime) } },
- new object[] { LegacyMods.Nightcore, new[] { typeof(TaikoModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(TaikoModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(TaikoModAutoplay) } },
- new object[] { LegacyMods.Perfect, new[] { typeof(TaikoModPerfect) } },
new object[] { LegacyMods.Random, new[] { typeof(TaikoModRandom) } },
- new object[] { LegacyMods.Cinema, new[] { typeof(TaikoModCinema) } },
new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(TaikoModHardRock), typeof(TaikoModDoubleTime) } }
};
+ [TestCaseSource(nameof(taiko_mod_mapping))]
+ [TestCase(LegacyMods.Cinema, new[] { typeof(TaikoModCinema) })]
+ [TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(TaikoModCinema) })]
+ [TestCase(LegacyMods.Nightcore, new[] { typeof(TaikoModNightcore) })]
+ [TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(TaikoModNightcore) })]
+ [TestCase(LegacyMods.Perfect, new[] { typeof(TaikoModPerfect) })]
+ [TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(TaikoModPerfect) })]
+ public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
+
[TestCaseSource(nameof(taiko_mod_mapping))]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(TaikoModCinema) })]
[TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(TaikoModNightcore) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(TaikoModPerfect) })]
- public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
-
- [TestCaseSource(nameof(taiko_mod_mapping))]
public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new TaikoRuleset();
diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs
index 00a667521d..fd1f564f59 100644
--- a/osu.Game.Tests/Database/RealmLiveTests.cs
+++ b/osu.Game.Tests/Database/RealmLiveTests.cs
@@ -91,6 +91,25 @@ public void TestAccessNonManaged()
Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
}
+ [Test]
+ public void TestTransactionRolledBackOnException()
+ {
+ RunTestWithRealm((realm, _) =>
+ {
+ var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
+
+ realm.Run(r => r.Write(_ => r.Add(beatmap)));
+
+ var liveBeatmap = beatmap.ToLive(realm);
+
+ Assert.Throws(() => liveBeatmap.PerformWrite(l => throw new InvalidOperationException()));
+ Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
+
+ liveBeatmap.PerformWrite(l => l.Hidden = true);
+ Assert.IsTrue(liveBeatmap.PerformRead(l => l.Hidden));
+ });
+ }
+
[Test]
public void TestScopedReadWithoutContext()
{
diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
index a803974d30..216bd0fd3c 100644
--- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
+++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
@@ -44,8 +44,7 @@ public void TestDefaultDirectory()
[Test]
public void TestCustomDirectory()
{
- string customPath = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost())
{
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
@@ -63,7 +62,6 @@ public void TestCustomDirectory()
finally
{
host.Exit();
- cleanupPath(customPath);
}
}
}
@@ -71,8 +69,7 @@ public void TestCustomDirectory()
[Test]
public void TestSubDirectoryLookup()
{
- string customPath = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost())
{
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
@@ -97,7 +94,6 @@ public void TestSubDirectoryLookup()
finally
{
host.Exit();
- cleanupPath(customPath);
}
}
}
@@ -105,8 +101,7 @@ public void TestSubDirectoryLookup()
[Test]
public void TestMigration()
{
- string customPath = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost())
{
try
@@ -173,7 +168,6 @@ public void TestMigration()
finally
{
host.Exit();
- cleanupPath(customPath);
}
}
}
@@ -181,9 +175,8 @@ public void TestMigration()
[Test]
public void TestMigrationBetweenTwoTargets()
{
- string customPath = prepareCustomPath();
- string customPath2 = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
+ using (prepareCustomPath(out string customPath2))
using (var host = new CustomTestHeadlessGameHost())
{
try
@@ -205,8 +198,6 @@ public void TestMigrationBetweenTwoTargets()
finally
{
host.Exit();
- cleanupPath(customPath);
- cleanupPath(customPath2);
}
}
}
@@ -214,8 +205,7 @@ public void TestMigrationBetweenTwoTargets()
[Test]
public void TestMigrationToSameTargetFails()
{
- string customPath = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost())
{
try
@@ -228,7 +218,6 @@ public void TestMigrationToSameTargetFails()
finally
{
host.Exit();
- cleanupPath(customPath);
}
}
}
@@ -236,9 +225,8 @@ public void TestMigrationToSameTargetFails()
[Test]
public void TestMigrationFailsOnExistingData()
{
- string customPath = prepareCustomPath();
- string customPath2 = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
+ using (prepareCustomPath(out string customPath2))
using (var host = new CustomTestHeadlessGameHost())
{
try
@@ -267,8 +255,6 @@ public void TestMigrationFailsOnExistingData()
finally
{
host.Exit();
- cleanupPath(customPath);
- cleanupPath(customPath2);
}
}
}
@@ -276,8 +262,7 @@ public void TestMigrationFailsOnExistingData()
[Test]
public void TestMigrationToNestedTargetFails()
{
- string customPath = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost())
{
try
@@ -298,7 +283,6 @@ public void TestMigrationToNestedTargetFails()
finally
{
host.Exit();
- cleanupPath(customPath);
}
}
}
@@ -306,8 +290,7 @@ public void TestMigrationToNestedTargetFails()
[Test]
public void TestMigrationToSeeminglyNestedTarget()
{
- string customPath = prepareCustomPath();
-
+ using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost())
{
try
@@ -328,7 +311,6 @@ public void TestMigrationToSeeminglyNestedTarget()
finally
{
host.Exit();
- cleanupPath(customPath);
}
}
}
@@ -343,14 +325,17 @@ private static string getDefaultLocationFor(CustomTestHeadlessGameHost host)
return path;
}
- private static string prepareCustomPath() => Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, $"custom-path-{Guid.NewGuid()}");
+ private static IDisposable prepareCustomPath(out string path)
+ {
+ path = Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, $"custom-path-{Guid.NewGuid()}");
+ return new InvokeOnDisposal(path, cleanupPath);
+ }
private static void cleanupPath(string path)
{
try
{
- if (Directory.Exists(path))
- Directory.Delete(path, true);
+ if (Directory.Exists(path)) Directory.Delete(path, true);
}
catch
{
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs
index a21ef6f897..327d581e37 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs
@@ -6,18 +6,14 @@
using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions;
-using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
-using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
-using osu.Game.Screens.Edit.Components.Timelines.Summary;
using osu.Game.Screens.Edit.GameplayTest;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
-using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
{
@@ -36,20 +32,21 @@ public void TestEditorGameplayTestAlwaysUsesOriginalRuleset()
() => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
&& Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect
&& songSelect.IsLoaded);
- AddUntilStep("wait for completion notification", () => Game.Notifications.ChildrenOfType().Count() == 1);
- AddStep("dismiss notifications", () => Game.Notifications.Hide());
AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo);
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
- AddStep("test gameplay", () =>
+ AddStep("test gameplay", () => ((Editor)Game.ScreenStack.CurrentScreen).TestGameplay());
+
+ AddUntilStep("wait for player", () =>
{
- var testGameplayButton = this.ChildrenOfType().Single();
- InputManager.MoveMouseTo(testGameplayButton);
- InputManager.Click(MouseButton.Left);
+ // notifications may fire at almost any inopportune time and cause annoying test failures.
+ // relentlessly attempt to dismiss any and all interfering overlays, which includes notifications.
+ // this is theoretically not foolproof, but it's the best that can be done here.
+ Game.CloseAllOverlays();
+ return Game.ScreenStack.CurrentScreen is EditorPlayer editorPlayer && editorPlayer.IsLoaded;
});
- AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen is EditorPlayer editorPlayer && editorPlayer.IsLoaded);
AddAssert("current ruleset is osu!", () => Game.Ruleset.Value.Equals(new OsuRuleset().RulesetInfo));
AddStep("exit to song select", () => Game.PerformFromScreen(_ => { }, typeof(PlaySongSelect).Yield()));
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 019bfe322e..47c8dc0f8d 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -6,10 +6,10 @@
using System.ComponentModel;
using System.Linq;
using osu.Framework.Testing;
-using osu.Game.Beatmaps.Timing;
using osu.Game.Graphics.Containers;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.Break;
@@ -31,19 +31,20 @@ protected override Player CreatePlayer(Ruleset ruleset)
protected override void AddCheckSteps()
{
+ // It doesn't matter which ruleset is used - this beatmap is only used for reference.
+ var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
+
AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
- seekToBreak(0);
+
+ seekTo(beatmap.Beatmap.Breaks[0].StartTime);
AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType().Single().AccuracyDisplay.Current.Value == 1);
+
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
- seekToBreak(0);
- seekToBreak(1);
-
- AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
-
+ seekTo(beatmap.Beatmap.HitObjects[^1].GetEndTime());
AddUntilStep("results displayed", () => getResultsScreen()?.IsLoaded == true);
AddAssert("score has combo", () => getResultsScreen().Score.Combo > 100);
@@ -58,12 +59,18 @@ ClickableAvatar getAvatar() => getResultsScreen()
ResultsScreen getResultsScreen() => Stack.CurrentScreen as ResultsScreen;
}
- private void seekToBreak(int breakIndex)
+ private void seekTo(double time)
{
- AddStep($"seek to break {breakIndex}", () => Player.GameplayClockContainer.Seek(destBreak().StartTime));
- AddUntilStep("wait for seek to complete", () => Player.DrawableRuleset.FrameStableClock.CurrentTime >= destBreak().StartTime);
+ AddStep($"seek to {time}", () => Player.GameplayClockContainer.Seek(time));
- BreakPeriod destBreak() => Beatmap.Value.Beatmap.Breaks.ElementAt(breakIndex);
+ // Prevent test timeouts by seeking in 10 second increments.
+ for (double t = 0; t < time; t += 10000)
+ {
+ double expectedTime = t;
+ AddUntilStep($"current time >= {t}", () => Player.DrawableRuleset.FrameStableClock.CurrentTime >= expectedTime);
+ }
+
+ AddUntilStep("wait for seek to complete", () => Player.DrawableRuleset.FrameStableClock.CurrentTime >= time);
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
index d2d9b9a9e5..247ea52648 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
@@ -39,7 +39,8 @@ public class TestSceneChatOverlay : OsuManualInputManagerTestScene
private TestChatOverlay chatOverlay;
private ChannelManager channelManager;
- private APIUser testUser;
+ private readonly APIUser testUser = new APIUser { Username = "test user", Id = 5071479 };
+
private Channel[] testChannels;
private Channel testChannel1 => testChannels[0];
@@ -51,7 +52,6 @@ public class TestSceneChatOverlay : OsuManualInputManagerTestScene
[SetUp]
public void SetUp() => Schedule(() =>
{
- testUser = new APIUser { Username = "test user", Id = 5071479 };
testChannels = Enumerable.Range(1, 10).Select(createPublicChannel).ToArray();
Child = new DependencyProvidingContainer
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 6d881555da..6896b442e0 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -100,12 +100,13 @@ public void TestPlaceholderBeatmapPresence()
[Test]
public void TestPlaceholderConvertSetting()
{
- changeRuleset(2);
addRulesetImportStep(0);
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
createSongSelect();
+ changeRuleset(2);
+
AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible);
AddStep("click link in placeholder", () => getPlaceholder().ChildrenOfType().First().TriggerClick());
diff --git a/osu.Game/Database/RealmLive.cs b/osu.Game/Database/RealmLive.cs
index 72de747807..9c871a3929 100644
--- a/osu.Game/Database/RealmLive.cs
+++ b/osu.Game/Database/RealmLive.cs
@@ -104,9 +104,12 @@ public override void PerformWrite(Action perform)
PerformRead(t =>
{
- var transaction = t.Realm.BeginWrite();
- perform(t);
- transaction.Commit();
+ using (var transaction = t.Realm.BeginWrite())
+ {
+ perform(t);
+ transaction.Commit();
+ }
+
RealmLiveStatistics.WRITES.Value++;
});
}
diff --git a/osu.Game/Models/RealmNamedFileUsage.cs b/osu.Game/Models/RealmNamedFileUsage.cs
index 0f6f439d73..c4310c4edb 100644
--- a/osu.Game/Models/RealmNamedFileUsage.cs
+++ b/osu.Game/Models/RealmNamedFileUsage.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using JetBrains.Annotations;
using osu.Framework.Testing;
using osu.Game.Database;
@@ -19,8 +20,8 @@ public class RealmNamedFileUsage : EmbeddedObject, INamedFile, INamedFileUsage
public RealmNamedFileUsage(RealmFile file, string filename)
{
- File = file;
- Filename = filename;
+ File = file ?? throw new ArgumentNullException(nameof(file));
+ Filename = filename ?? throw new ArgumentNullException(nameof(filename));
}
[UsedImplicitly]
diff --git a/osu.Game/Online/Rooms/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs
index a0711d9ded..2213311c67 100644
--- a/osu.Game/Online/Rooms/PlaylistItem.cs
+++ b/osu.Game/Online/Rooms/PlaylistItem.cs
@@ -72,7 +72,7 @@ private int onlineBeatmapId
/// In many cases, this will *not* contain any usable information apart from OnlineID.
///
[JsonIgnore]
- public IBeatmapInfo Beatmap { get; set; } = null!;
+ public IBeatmapInfo Beatmap { get; private set; }
[JsonIgnore]
public IBindable Valid => valid;
@@ -81,6 +81,7 @@ private int onlineBeatmapId
[JsonConstructor]
private PlaylistItem()
+ : this(new APIBeatmap())
{
}
diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs
index e098472999..c1ec6c30ef 100644
--- a/osu.Game/Rulesets/Ruleset.cs
+++ b/osu.Game/Rulesets/Ruleset.cs
@@ -143,7 +143,7 @@ public virtual LegacyMods ConvertToLegacyMods(Mod[] mods)
break;
case ModPerfect:
- value |= LegacyMods.Perfect;
+ value |= LegacyMods.Perfect | LegacyMods.SuddenDeath;
break;
case ModSuddenDeath:
@@ -151,7 +151,7 @@ public virtual LegacyMods ConvertToLegacyMods(Mod[] mods)
break;
case ModNightcore:
- value |= LegacyMods.Nightcore;
+ value |= LegacyMods.Nightcore | LegacyMods.DoubleTime;
break;
case ModDoubleTime:
@@ -171,7 +171,7 @@ public virtual LegacyMods ConvertToLegacyMods(Mod[] mods)
break;
case ModCinema:
- value |= LegacyMods.Cinema;
+ value |= LegacyMods.Cinema | LegacyMods.Autoplay;
break;
case ModAutoplay:
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index ab690b22a6..ff223f5107 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index a84fc40a45..b8a4aca02e 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -61,7 +61,7 @@
-
+
@@ -84,7 +84,7 @@
-
+