1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 00:42:55 +08:00

Merge branch 'master' into realm-fix-async-write-after-disposal

This commit is contained in:
Dean Herbert 2022-06-30 19:07:15 +09:00 committed by GitHub
commit 447b496eff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 113 additions and 87 deletions

View File

@ -52,7 +52,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.628.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2022.628.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.628.1" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2022.629.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Transitive Dependencies"> <ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. --> <!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->

View File

@ -24,21 +24,24 @@ namespace osu.Game.Rulesets.Catch.Tests
new object[] { LegacyMods.DoubleTime, new[] { typeof(CatchModDoubleTime) } }, new object[] { LegacyMods.DoubleTime, new[] { typeof(CatchModDoubleTime) } },
new object[] { LegacyMods.Relax, new[] { typeof(CatchModRelax) } }, new object[] { LegacyMods.Relax, new[] { typeof(CatchModRelax) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(CatchModHalfTime) } }, new object[] { LegacyMods.HalfTime, new[] { typeof(CatchModHalfTime) } },
new object[] { LegacyMods.Nightcore, new[] { typeof(CatchModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(CatchModFlashlight) } }, new object[] { LegacyMods.Flashlight, new[] { typeof(CatchModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(CatchModAutoplay) } }, 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) } } 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))] [TestCaseSource(nameof(catch_mod_mapping))]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(CatchModCinema) })] [TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(CatchModCinema) })]
[TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(CatchModNightcore) })] [TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(CatchModNightcore) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, 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))]
public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods); public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new CatchRuleset(); protected override Ruleset CreateRuleset() => new CatchRuleset();

View File

@ -23,10 +23,8 @@ namespace osu.Game.Rulesets.Mania.Tests
new object[] { LegacyMods.SuddenDeath, new[] { typeof(ManiaModSuddenDeath) } }, new object[] { LegacyMods.SuddenDeath, new[] { typeof(ManiaModSuddenDeath) } },
new object[] { LegacyMods.DoubleTime, new[] { typeof(ManiaModDoubleTime) } }, new object[] { LegacyMods.DoubleTime, new[] { typeof(ManiaModDoubleTime) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(ManiaModHalfTime) } }, new object[] { LegacyMods.HalfTime, new[] { typeof(ManiaModHalfTime) } },
new object[] { LegacyMods.Nightcore, new[] { typeof(ManiaModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(ManiaModFlashlight) } }, new object[] { LegacyMods.Flashlight, new[] { typeof(ManiaModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(ManiaModAutoplay) } }, new object[] { LegacyMods.Autoplay, new[] { typeof(ManiaModAutoplay) } },
new object[] { LegacyMods.Perfect, new[] { typeof(ManiaModPerfect) } },
new object[] { LegacyMods.Key4, new[] { typeof(ManiaModKey4) } }, new object[] { LegacyMods.Key4, new[] { typeof(ManiaModKey4) } },
new object[] { LegacyMods.Key5, new[] { typeof(ManiaModKey5) } }, new object[] { LegacyMods.Key5, new[] { typeof(ManiaModKey5) } },
new object[] { LegacyMods.Key6, new[] { typeof(ManiaModKey6) } }, new object[] { LegacyMods.Key6, new[] { typeof(ManiaModKey6) } },
@ -34,7 +32,6 @@ namespace osu.Game.Rulesets.Mania.Tests
new object[] { LegacyMods.Key8, new[] { typeof(ManiaModKey8) } }, new object[] { LegacyMods.Key8, new[] { typeof(ManiaModKey8) } },
new object[] { LegacyMods.FadeIn, new[] { typeof(ManiaModFadeIn) } }, new object[] { LegacyMods.FadeIn, new[] { typeof(ManiaModFadeIn) } },
new object[] { LegacyMods.Random, new[] { typeof(ManiaModRandom) } }, new object[] { LegacyMods.Random, new[] { typeof(ManiaModRandom) } },
new object[] { LegacyMods.Cinema, new[] { typeof(ManiaModCinema) } },
new object[] { LegacyMods.Key9, new[] { typeof(ManiaModKey9) } }, new object[] { LegacyMods.Key9, new[] { typeof(ManiaModKey9) } },
new object[] { LegacyMods.KeyCoop, new[] { typeof(ManiaModDualStages) } }, new object[] { LegacyMods.KeyCoop, new[] { typeof(ManiaModDualStages) } },
new object[] { LegacyMods.Key1, new[] { typeof(ManiaModKey1) } }, new object[] { LegacyMods.Key1, new[] { typeof(ManiaModKey1) } },
@ -45,12 +42,18 @@ namespace osu.Game.Rulesets.Mania.Tests
}; };
[TestCaseSource(nameof(mania_mod_mapping))] [TestCaseSource(nameof(mania_mod_mapping))]
[TestCase(LegacyMods.Cinema, new[] { typeof(ManiaModCinema) })]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, 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.Nightcore | LegacyMods.DoubleTime, new[] { typeof(ManiaModNightcore) })]
[TestCase(LegacyMods.Perfect, new[] { typeof(ManiaModPerfect) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(ManiaModPerfect) })] [TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(ManiaModPerfect) })]
public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods); public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
[TestCaseSource(nameof(mania_mod_mapping))] [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); public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new ManiaRuleset(); protected override Ruleset CreateRuleset() => new ManiaRuleset();

View File

@ -25,24 +25,27 @@ namespace osu.Game.Rulesets.Osu.Tests
new object[] { LegacyMods.DoubleTime, new[] { typeof(OsuModDoubleTime) } }, new object[] { LegacyMods.DoubleTime, new[] { typeof(OsuModDoubleTime) } },
new object[] { LegacyMods.Relax, new[] { typeof(OsuModRelax) } }, new object[] { LegacyMods.Relax, new[] { typeof(OsuModRelax) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(OsuModHalfTime) } }, new object[] { LegacyMods.HalfTime, new[] { typeof(OsuModHalfTime) } },
new object[] { LegacyMods.Nightcore, new[] { typeof(OsuModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(OsuModFlashlight) } }, new object[] { LegacyMods.Flashlight, new[] { typeof(OsuModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(OsuModAutoplay) } }, new object[] { LegacyMods.Autoplay, new[] { typeof(OsuModAutoplay) } },
new object[] { LegacyMods.SpunOut, new[] { typeof(OsuModSpunOut) } }, new object[] { LegacyMods.SpunOut, new[] { typeof(OsuModSpunOut) } },
new object[] { LegacyMods.Autopilot, new[] { typeof(OsuModAutopilot) } }, 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.Target, new[] { typeof(OsuModTarget) } },
new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(OsuModHardRock), typeof(OsuModDoubleTime) } } new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(OsuModHardRock), typeof(OsuModDoubleTime) } }
}; };
[TestCaseSource(nameof(osu_mod_mapping))] [TestCaseSource(nameof(osu_mod_mapping))]
[TestCase(LegacyMods.Cinema, new[] { typeof(OsuModCinema) })]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, 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.Nightcore | LegacyMods.DoubleTime, new[] { typeof(OsuModNightcore) })]
[TestCase(LegacyMods.Perfect, new[] { typeof(OsuModPerfect) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(OsuModPerfect) })] [TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, new[] { typeof(OsuModPerfect) })]
public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods); public new void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) => base.TestFromLegacy(legacyMods, expectedMods);
[TestCaseSource(nameof(osu_mod_mapping))] [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); public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new OsuRuleset(); protected override Ruleset CreateRuleset() => new OsuRuleset();

View File

@ -24,22 +24,25 @@ namespace osu.Game.Rulesets.Taiko.Tests
new object[] { LegacyMods.DoubleTime, new[] { typeof(TaikoModDoubleTime) } }, new object[] { LegacyMods.DoubleTime, new[] { typeof(TaikoModDoubleTime) } },
new object[] { LegacyMods.Relax, new[] { typeof(TaikoModRelax) } }, new object[] { LegacyMods.Relax, new[] { typeof(TaikoModRelax) } },
new object[] { LegacyMods.HalfTime, new[] { typeof(TaikoModHalfTime) } }, new object[] { LegacyMods.HalfTime, new[] { typeof(TaikoModHalfTime) } },
new object[] { LegacyMods.Nightcore, new[] { typeof(TaikoModNightcore) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(TaikoModFlashlight) } }, new object[] { LegacyMods.Flashlight, new[] { typeof(TaikoModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(TaikoModAutoplay) } }, new object[] { LegacyMods.Autoplay, new[] { typeof(TaikoModAutoplay) } },
new object[] { LegacyMods.Perfect, new[] { typeof(TaikoModPerfect) } },
new object[] { LegacyMods.Random, new[] { typeof(TaikoModRandom) } }, 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) } } 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))] [TestCaseSource(nameof(taiko_mod_mapping))]
[TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(TaikoModCinema) })] [TestCase(LegacyMods.Cinema | LegacyMods.Autoplay, new[] { typeof(TaikoModCinema) })]
[TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(TaikoModNightcore) })] [TestCase(LegacyMods.Nightcore | LegacyMods.DoubleTime, new[] { typeof(TaikoModNightcore) })]
[TestCase(LegacyMods.Perfect | LegacyMods.SuddenDeath, 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))]
public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods); public new void TestToLegacy(LegacyMods legacyMods, Type[] givenMods) => base.TestToLegacy(legacyMods, givenMods);
protected override Ruleset CreateRuleset() => new TaikoRuleset(); protected override Ruleset CreateRuleset() => new TaikoRuleset();

View File

@ -91,6 +91,25 @@ namespace osu.Game.Tests.Database
Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); 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<InvalidOperationException>(() => 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] [Test]
public void TestScopedReadWithoutContext() public void TestScopedReadWithoutContext()
{ {

View File

@ -44,8 +44,7 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestCustomDirectory() public void TestCustomDirectory()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
using (var storageConfig = new StorageConfigManager(host.InitialStorage)) using (var storageConfig = new StorageConfigManager(host.InitialStorage))
@ -63,7 +62,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
} }
} }
} }
@ -71,8 +69,7 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestSubDirectoryLookup() public void TestSubDirectoryLookup()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
using (var storageConfig = new StorageConfigManager(host.InitialStorage)) using (var storageConfig = new StorageConfigManager(host.InitialStorage))
@ -97,7 +94,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
} }
} }
} }
@ -105,8 +101,7 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestMigration() public void TestMigration()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
try try
@ -173,7 +168,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
} }
} }
} }
@ -181,9 +175,8 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestMigrationBetweenTwoTargets() public void TestMigrationBetweenTwoTargets()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
string customPath2 = prepareCustomPath(); using (prepareCustomPath(out string customPath2))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
try try
@ -205,8 +198,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
cleanupPath(customPath2);
} }
} }
} }
@ -214,8 +205,7 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestMigrationToSameTargetFails() public void TestMigrationToSameTargetFails()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
try try
@ -228,7 +218,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
} }
} }
} }
@ -236,9 +225,8 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestMigrationFailsOnExistingData() public void TestMigrationFailsOnExistingData()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
string customPath2 = prepareCustomPath(); using (prepareCustomPath(out string customPath2))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
try try
@ -267,8 +255,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
cleanupPath(customPath2);
} }
} }
} }
@ -276,8 +262,7 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestMigrationToNestedTargetFails() public void TestMigrationToNestedTargetFails()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
try try
@ -298,7 +283,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
} }
} }
} }
@ -306,8 +290,7 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestMigrationToSeeminglyNestedTarget() public void TestMigrationToSeeminglyNestedTarget()
{ {
string customPath = prepareCustomPath(); using (prepareCustomPath(out string customPath))
using (var host = new CustomTestHeadlessGameHost()) using (var host = new CustomTestHeadlessGameHost())
{ {
try try
@ -328,7 +311,6 @@ namespace osu.Game.Tests.NonVisual
finally finally
{ {
host.Exit(); host.Exit();
cleanupPath(customPath);
} }
} }
} }
@ -343,14 +325,17 @@ namespace osu.Game.Tests.NonVisual
return path; 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<string>(path, cleanupPath);
}
private static void cleanupPath(string path) private static void cleanupPath(string path)
{ {
try try
{ {
if (Directory.Exists(path)) if (Directory.Exists(path)) Directory.Delete(path, true);
Directory.Delete(path, true);
} }
catch catch
{ {

View File

@ -6,18 +6,14 @@ using NUnit.Framework;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components.Timelines.Summary;
using osu.Game.Screens.Edit.GameplayTest; using osu.Game.Screens.Edit.GameplayTest;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
using osu.Game.Tests.Resources; using osu.Game.Tests.Resources;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing namespace osu.Game.Tests.Visual.Editing
{ {
@ -36,20 +32,21 @@ namespace osu.Game.Tests.Visual.Editing
() => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet) () => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
&& Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect
&& songSelect.IsLoaded); && songSelect.IsLoaded);
AddUntilStep("wait for completion notification", () => Game.Notifications.ChildrenOfType<ProgressCompletionNotification>().Count() == 1);
AddStep("dismiss notifications", () => Game.Notifications.Hide());
AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo); 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))); 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); 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<TestGameplayButton>().Single(); // notifications may fire at almost any inopportune time and cause annoying test failures.
InputManager.MoveMouseTo(testGameplayButton); // relentlessly attempt to dismiss any and all interfering overlays, which includes notifications.
InputManager.Click(MouseButton.Left); // 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)); AddAssert("current ruleset is osu!", () => Game.Ruleset.Value.Equals(new OsuRuleset().RulesetInfo));
AddStep("exit to song select", () => Game.PerformFromScreen(_ => { }, typeof(PlaySongSelect).Yield())); AddStep("exit to song select", () => Game.PerformFromScreen(_ => { }, typeof(PlaySongSelect).Yield()));

View File

@ -6,10 +6,10 @@
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps.Timing;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Screens.Play.Break; using osu.Game.Screens.Play.Break;
@ -31,19 +31,20 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override void AddCheckSteps() 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("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2)); 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("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType<BreakInfo>().Single().AccuracyDisplay.Current.Value == 1); AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType<BreakInfo>().Single().AccuracyDisplay.Current.Value == 1);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000)); AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
seekToBreak(0); seekTo(beatmap.Beatmap.HitObjects[^1].GetEndTime());
seekToBreak(1);
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
AddUntilStep("results displayed", () => getResultsScreen()?.IsLoaded == true); AddUntilStep("results displayed", () => getResultsScreen()?.IsLoaded == true);
AddAssert("score has combo", () => getResultsScreen().Score.Combo > 100); AddAssert("score has combo", () => getResultsScreen().Score.Combo > 100);
@ -58,12 +59,18 @@ namespace osu.Game.Tests.Visual.Gameplay
ResultsScreen getResultsScreen() => Stack.CurrentScreen as ResultsScreen; 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)); AddStep($"seek to {time}", () => Player.GameplayClockContainer.Seek(time));
AddUntilStep("wait for seek to complete", () => Player.DrawableRuleset.FrameStableClock.CurrentTime >= destBreak().StartTime);
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);
} }
} }
} }

View File

@ -39,7 +39,8 @@ namespace osu.Game.Tests.Visual.Online
private TestChatOverlay chatOverlay; private TestChatOverlay chatOverlay;
private ChannelManager channelManager; private ChannelManager channelManager;
private APIUser testUser; private readonly APIUser testUser = new APIUser { Username = "test user", Id = 5071479 };
private Channel[] testChannels; private Channel[] testChannels;
private Channel testChannel1 => testChannels[0]; private Channel testChannel1 => testChannels[0];
@ -51,7 +52,6 @@ namespace osu.Game.Tests.Visual.Online
[SetUp] [SetUp]
public void SetUp() => Schedule(() => public void SetUp() => Schedule(() =>
{ {
testUser = new APIUser { Username = "test user", Id = 5071479 };
testChannels = Enumerable.Range(1, 10).Select(createPublicChannel).ToArray(); testChannels = Enumerable.Range(1, 10).Select(createPublicChannel).ToArray();
Child = new DependencyProvidingContainer Child = new DependencyProvidingContainer

View File

@ -100,12 +100,13 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test] [Test]
public void TestPlaceholderConvertSetting() public void TestPlaceholderConvertSetting()
{ {
changeRuleset(2);
addRulesetImportStep(0); addRulesetImportStep(0);
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, false)); AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
createSongSelect(); createSongSelect();
changeRuleset(2);
AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible); AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible);
AddStep("click link in placeholder", () => getPlaceholder().ChildrenOfType<DrawableLinkCompiler>().First().TriggerClick()); AddStep("click link in placeholder", () => getPlaceholder().ChildrenOfType<DrawableLinkCompiler>().First().TriggerClick());

View File

@ -104,9 +104,12 @@ namespace osu.Game.Database
PerformRead(t => PerformRead(t =>
{ {
var transaction = t.Realm.BeginWrite(); using (var transaction = t.Realm.BeginWrite())
{
perform(t); perform(t);
transaction.Commit(); transaction.Commit();
}
RealmLiveStatistics.WRITES.Value++; RealmLiveStatistics.WRITES.Value++;
}); });
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Database; using osu.Game.Database;
@ -19,8 +20,8 @@ namespace osu.Game.Models
public RealmNamedFileUsage(RealmFile file, string filename) public RealmNamedFileUsage(RealmFile file, string filename)
{ {
File = file; File = file ?? throw new ArgumentNullException(nameof(file));
Filename = filename; Filename = filename ?? throw new ArgumentNullException(nameof(filename));
} }
[UsedImplicitly] [UsedImplicitly]

View File

@ -72,7 +72,7 @@ namespace osu.Game.Online.Rooms
/// In many cases, this will *not* contain any usable information apart from OnlineID. /// In many cases, this will *not* contain any usable information apart from OnlineID.
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public IBeatmapInfo Beatmap { get; set; } = null!; public IBeatmapInfo Beatmap { get; private set; }
[JsonIgnore] [JsonIgnore]
public IBindable<bool> Valid => valid; public IBindable<bool> Valid => valid;
@ -81,6 +81,7 @@ namespace osu.Game.Online.Rooms
[JsonConstructor] [JsonConstructor]
private PlaylistItem() private PlaylistItem()
: this(new APIBeatmap())
{ {
} }

View File

@ -143,7 +143,7 @@ namespace osu.Game.Rulesets
break; break;
case ModPerfect: case ModPerfect:
value |= LegacyMods.Perfect; value |= LegacyMods.Perfect | LegacyMods.SuddenDeath;
break; break;
case ModSuddenDeath: case ModSuddenDeath:
@ -151,7 +151,7 @@ namespace osu.Game.Rulesets
break; break;
case ModNightcore: case ModNightcore:
value |= LegacyMods.Nightcore; value |= LegacyMods.Nightcore | LegacyMods.DoubleTime;
break; break;
case ModDoubleTime: case ModDoubleTime:
@ -171,7 +171,7 @@ namespace osu.Game.Rulesets
break; break;
case ModCinema: case ModCinema:
value |= LegacyMods.Cinema; value |= LegacyMods.Cinema | LegacyMods.Autoplay;
break; break;
case ModAutoplay: case ModAutoplay:

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Realm" Version="10.14.0" /> <PackageReference Include="Realm" Version="10.14.0" />
<PackageReference Include="ppy.osu.Framework" Version="2022.628.1" /> <PackageReference Include="ppy.osu.Framework" Version="2022.629.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.628.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2022.628.0" />
<PackageReference Include="Sentry" Version="3.17.1" /> <PackageReference Include="Sentry" Version="3.17.1" />
<PackageReference Include="SharpCompress" Version="0.31.0" /> <PackageReference Include="SharpCompress" Version="0.31.0" />

View File

@ -61,7 +61,7 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.628.1" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2022.629.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.628.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2022.628.0" />
</ItemGroup> </ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) --> <!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
@ -84,7 +84,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2022.628.1" /> <PackageReference Include="ppy.osu.Framework" Version="2022.629.0" />
<PackageReference Include="SharpCompress" Version="0.31.0" /> <PackageReference Include="SharpCompress" Version="0.31.0" />
<PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />