mirror of
https://github.com/ppy/osu.git
synced 2024-11-12 01:07:25 +08:00
6100bf66a6
After the recent changes introducing cancellation support to `WorkingBeatmap`, it turned out that if the cancellation support was used, `GetPlayableBeatmap()` would raise timeout exceptions rather than the expected `OperationCanceledException`. To that end, split off a separate overload for the typical usage, that catches `OperationCanceledException` and converts them to beatmap load timeout exceptions, and use normal `OperationCanceledException`s in the overload that requires a cancellation token to work.
116 lines
3.7 KiB
C#
116 lines
3.7 KiB
C#
// 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.Threading;
|
|
using System.Threading.Tasks;
|
|
using Moq;
|
|
using NUnit.Framework;
|
|
using osu.Game.Beatmaps;
|
|
using osu.Game.Rulesets;
|
|
using osu.Game.Rulesets.Mods;
|
|
using osu.Game.Rulesets.Objects;
|
|
using osu.Game.Rulesets.Osu;
|
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
|
|
|
namespace osu.Game.Tests.Beatmaps
|
|
{
|
|
[TestFixture]
|
|
public class WorkingBeatmapTest
|
|
{
|
|
[Test]
|
|
public void TestGetPlayableSuccess()
|
|
{
|
|
var working = new TestNeverLoadsWorkingBeatmap();
|
|
|
|
working.ResetEvent.Set();
|
|
|
|
Assert.NotNull(working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo));
|
|
}
|
|
|
|
[Test]
|
|
public void TestGetPlayableCancellationToken()
|
|
{
|
|
var working = new TestNeverLoadsWorkingBeatmap();
|
|
|
|
var cts = new CancellationTokenSource();
|
|
var loadStarted = new ManualResetEventSlim();
|
|
var loadCompleted = new ManualResetEventSlim();
|
|
|
|
Task.Factory.StartNew(() =>
|
|
{
|
|
loadStarted.Set();
|
|
Assert.Throws<OperationCanceledException>(() => working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty<Mod>(), cts.Token));
|
|
loadCompleted.Set();
|
|
}, TaskCreationOptions.LongRunning);
|
|
|
|
Assert.IsTrue(loadStarted.Wait(10000));
|
|
|
|
cts.Cancel();
|
|
|
|
Assert.IsTrue(loadCompleted.Wait(10000));
|
|
|
|
working.ResetEvent.Set();
|
|
}
|
|
|
|
[Test]
|
|
public void TestGetPlayableDefaultTimeout()
|
|
{
|
|
var working = new TestNeverLoadsWorkingBeatmap();
|
|
|
|
Assert.Throws(Is.InstanceOf<TimeoutException>(), () => working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo));
|
|
|
|
working.ResetEvent.Set();
|
|
}
|
|
|
|
[Test]
|
|
public void TestGetPlayableRulesetLoadFailure()
|
|
{
|
|
var working = new TestWorkingBeatmap(new Beatmap());
|
|
|
|
// by default mocks return nulls if not set up, which is actually desired here to simulate a ruleset load failure scenario.
|
|
var ruleset = new Mock<IRulesetInfo>();
|
|
|
|
Assert.Throws<RulesetLoadException>(() => working.GetPlayableBeatmap(ruleset.Object));
|
|
}
|
|
|
|
public class TestNeverLoadsWorkingBeatmap : TestWorkingBeatmap
|
|
{
|
|
public ManualResetEventSlim ResetEvent = new ManualResetEventSlim();
|
|
|
|
public TestNeverLoadsWorkingBeatmap()
|
|
: base(new Beatmap())
|
|
{
|
|
}
|
|
|
|
protected override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => new TestConverter(beatmap, ResetEvent);
|
|
|
|
public class TestConverter : IBeatmapConverter
|
|
{
|
|
private readonly ManualResetEventSlim resetEvent;
|
|
|
|
public TestConverter(IBeatmap beatmap, ManualResetEventSlim resetEvent)
|
|
{
|
|
this.resetEvent = resetEvent;
|
|
Beatmap = beatmap;
|
|
}
|
|
|
|
public event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
|
|
|
|
protected virtual void OnObjectConverted(HitObject arg1, IEnumerable<HitObject> arg2) => ObjectConverted?.Invoke(arg1, arg2);
|
|
|
|
public IBeatmap Beatmap { get; }
|
|
|
|
public bool CanConvert() => true;
|
|
|
|
public IBeatmap Convert(CancellationToken cancellationToken = default)
|
|
{
|
|
resetEvent.Wait(cancellationToken);
|
|
return new OsuBeatmap();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|