1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 07:42:57 +08:00

Merge pull request #9333 from bdach/ruleset-sample-tests

Extract abstract hitobject sample test class
This commit is contained in:
Dean Herbert 2020-06-22 11:53:58 +09:00 committed by GitHub
commit eb0433e04d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 219 additions and 204 deletions

View File

@ -1,52 +1,21 @@
// 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.IO;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Skinning;
using osu.Game.Storyboards;
using osu.Game.Rulesets.Osu;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.Gameplay;
using osu.Game.Users;
namespace osu.Game.Tests.Gameplay
{
[HeadlessTest]
public class TestSceneHitObjectSamples : OsuPlayerTestScene
public class TestSceneHitObjectSamples : HitObjectSampleTest
{
private readonly SkinInfo userSkinInfo = new SkinInfo();
private readonly BeatmapInfo beatmapInfo = new BeatmapInfo
{
BeatmapSet = new BeatmapSetInfo(),
Metadata = new BeatmapMetadata
{
Author = User.SYSTEM_USER
}
};
private readonly TestResourceStore userSkinResourceStore = new TestResourceStore();
private readonly TestResourceStore beatmapSkinResourceStore = new TestResourceStore();
protected override bool HasCustomSteps => true;
private SkinSourceDependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> new DependencyContainer(dependencies = new SkinSourceDependencyContainer(base.CreateChildDependencies(parent)));
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
protected override IResourceStore<byte[]> Resources => TestResources.GetStore();
/// <summary>
/// Tests that a hitobject which provides no custom sample set retrieves samples from the user skin.
@ -56,11 +25,11 @@ namespace osu.Game.Tests.Gameplay
{
const string expected_sample = "normal-hitnormal";
setupSkins(expected_sample, expected_sample);
SetupSkins(expected_sample, expected_sample);
createTestWithBeatmap("hitobject-skin-sample.osu");
CreateTestWithBeatmap("hitobject-skin-sample.osu");
assertUserLookup(expected_sample);
AssertUserLookup(expected_sample);
}
/// <summary>
@ -71,11 +40,11 @@ namespace osu.Game.Tests.Gameplay
{
const string expected_sample = "normal-hitnormal";
setupSkins(expected_sample, expected_sample);
SetupSkins(expected_sample, expected_sample);
createTestWithBeatmap("hitobject-beatmap-sample.osu");
CreateTestWithBeatmap("hitobject-beatmap-sample.osu");
assertBeatmapLookup(expected_sample);
AssertBeatmapLookup(expected_sample);
}
/// <summary>
@ -86,11 +55,11 @@ namespace osu.Game.Tests.Gameplay
{
const string expected_sample = "normal-hitnormal";
setupSkins(null, expected_sample);
SetupSkins(null, expected_sample);
createTestWithBeatmap("hitobject-beatmap-sample.osu");
CreateTestWithBeatmap("hitobject-beatmap-sample.osu");
assertUserLookup(expected_sample);
AssertUserLookup(expected_sample);
}
/// <summary>
@ -102,11 +71,11 @@ namespace osu.Game.Tests.Gameplay
[TestCase("normal-hitnormal")]
public void TestDefaultCustomSampleFromBeatmap(string expectedSample)
{
setupSkins(expectedSample, expectedSample);
SetupSkins(expectedSample, expectedSample);
createTestWithBeatmap("hitobject-beatmap-custom-sample.osu");
CreateTestWithBeatmap("hitobject-beatmap-custom-sample.osu");
assertBeatmapLookup(expectedSample);
AssertBeatmapLookup(expectedSample);
}
/// <summary>
@ -118,11 +87,11 @@ namespace osu.Game.Tests.Gameplay
[TestCase("normal-hitnormal")]
public void TestDefaultCustomSampleFromUserSkinFallback(string expectedSample)
{
setupSkins(string.Empty, expectedSample);
SetupSkins(string.Empty, expectedSample);
createTestWithBeatmap("hitobject-beatmap-custom-sample.osu");
CreateTestWithBeatmap("hitobject-beatmap-custom-sample.osu");
assertUserLookup(expectedSample);
AssertUserLookup(expectedSample);
}
/// <summary>
@ -133,11 +102,11 @@ namespace osu.Game.Tests.Gameplay
{
const string expected_sample = "hit_1.wav";
setupSkins(expected_sample, expected_sample);
SetupSkins(expected_sample, expected_sample);
createTestWithBeatmap("file-beatmap-sample.osu");
CreateTestWithBeatmap("file-beatmap-sample.osu");
assertBeatmapLookup(expected_sample);
AssertBeatmapLookup(expected_sample);
}
/// <summary>
@ -148,11 +117,11 @@ namespace osu.Game.Tests.Gameplay
{
const string expected_sample = "normal-hitnormal";
setupSkins(expected_sample, expected_sample);
SetupSkins(expected_sample, expected_sample);
createTestWithBeatmap("controlpoint-skin-sample.osu");
CreateTestWithBeatmap("controlpoint-skin-sample.osu");
assertUserLookup(expected_sample);
AssertUserLookup(expected_sample);
}
/// <summary>
@ -163,11 +132,11 @@ namespace osu.Game.Tests.Gameplay
{
const string expected_sample = "normal-hitnormal";
setupSkins(expected_sample, expected_sample);
SetupSkins(expected_sample, expected_sample);
createTestWithBeatmap("controlpoint-beatmap-sample.osu");
CreateTestWithBeatmap("controlpoint-beatmap-sample.osu");
assertBeatmapLookup(expected_sample);
AssertBeatmapLookup(expected_sample);
}
/// <summary>
@ -177,11 +146,11 @@ namespace osu.Game.Tests.Gameplay
[TestCase("normal-hitnormal")]
public void TestControlPointCustomSampleFromBeatmap(string sampleName)
{
setupSkins(sampleName, sampleName);
SetupSkins(sampleName, sampleName);
createTestWithBeatmap("controlpoint-beatmap-custom-sample.osu");
CreateTestWithBeatmap("controlpoint-beatmap-custom-sample.osu");
assertBeatmapLookup(sampleName);
AssertBeatmapLookup(sampleName);
}
/// <summary>
@ -192,149 +161,11 @@ namespace osu.Game.Tests.Gameplay
{
const string expected_sample = "normal-hitnormal3";
setupSkins(expected_sample, expected_sample);
SetupSkins(expected_sample, expected_sample);
createTestWithBeatmap("hitobject-beatmap-custom-sample-override.osu");
CreateTestWithBeatmap("hitobject-beatmap-custom-sample-override.osu");
assertBeatmapLookup(expected_sample);
}
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => currentTestBeatmap;
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
=> new TestWorkingBeatmap(beatmapInfo, beatmapSkinResourceStore, beatmap, storyboard, Clock, Audio);
private IBeatmap currentTestBeatmap;
private void createTestWithBeatmap(string filename)
{
CreateTest(() =>
{
AddStep("clear performed lookups", () =>
{
userSkinResourceStore.PerformedLookups.Clear();
beatmapSkinResourceStore.PerformedLookups.Clear();
});
AddStep($"load {filename}", () =>
{
using (var reader = new LineBufferedReader(TestResources.OpenResource($"SampleLookups/{filename}")))
currentTestBeatmap = Decoder.GetDecoder<Beatmap>(reader).Decode(reader);
});
});
}
private void setupSkins(string beatmapFile, string userFile)
{
AddStep("setup skins", () =>
{
userSkinInfo.Files = new List<SkinFileInfo>
{
new SkinFileInfo
{
Filename = userFile,
FileInfo = new IO.FileInfo { Hash = userFile }
}
};
beatmapInfo.BeatmapSet.Files = new List<BeatmapSetFileInfo>
{
new BeatmapSetFileInfo
{
Filename = beatmapFile,
FileInfo = new IO.FileInfo { Hash = beatmapFile }
}
};
// Need to refresh the cached skin source to refresh the skin resource store.
dependencies.SkinSource = new SkinProvidingContainer(new LegacySkin(userSkinInfo, userSkinResourceStore, Audio));
});
}
private void assertBeatmapLookup(string name) => AddAssert($"\"{name}\" looked up from beatmap skin",
() => !userSkinResourceStore.PerformedLookups.Contains(name) && beatmapSkinResourceStore.PerformedLookups.Contains(name));
private void assertUserLookup(string name) => AddAssert($"\"{name}\" looked up from user skin",
() => !beatmapSkinResourceStore.PerformedLookups.Contains(name) && userSkinResourceStore.PerformedLookups.Contains(name));
private class SkinSourceDependencyContainer : IReadOnlyDependencyContainer
{
public ISkinSource SkinSource;
private readonly IReadOnlyDependencyContainer fallback;
public SkinSourceDependencyContainer(IReadOnlyDependencyContainer fallback)
{
this.fallback = fallback;
}
public object Get(Type type)
{
if (type == typeof(ISkinSource))
return SkinSource;
return fallback.Get(type);
}
public object Get(Type type, CacheInfo info)
{
if (type == typeof(ISkinSource))
return SkinSource;
return fallback.Get(type, info);
}
public void Inject<T>(T instance) where T : class
{
// Never used directly
}
}
private class TestResourceStore : IResourceStore<byte[]>
{
public readonly List<string> PerformedLookups = new List<string>();
public byte[] Get(string name)
{
markLookup(name);
return Array.Empty<byte>();
}
public Task<byte[]> GetAsync(string name)
{
markLookup(name);
return Task.FromResult(Array.Empty<byte>());
}
public Stream GetStream(string name)
{
markLookup(name);
return new MemoryStream();
}
private void markLookup(string name) => PerformedLookups.Add(name.Substring(name.LastIndexOf(Path.DirectorySeparatorChar) + 1));
public IEnumerable<string> GetAvailableResources() => Enumerable.Empty<string>();
public void Dispose()
{
}
}
private class TestWorkingBeatmap : ClockBackedTestWorkingBeatmap
{
private readonly BeatmapInfo skinBeatmapInfo;
private readonly IResourceStore<byte[]> resourceStore;
public TestWorkingBeatmap(BeatmapInfo skinBeatmapInfo, IResourceStore<byte[]> resourceStore, IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio,
double length = 60000)
: base(beatmap, storyboard, referenceClock, audio, length)
{
this.skinBeatmapInfo = skinBeatmapInfo;
this.resourceStore = resourceStore;
}
protected override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, AudioManager);
AssertBeatmapLookup(expected_sample);
}
}
}

View File

@ -0,0 +1,184 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.IO.Stores;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Skinning;
using osu.Game.Storyboards;
using osu.Game.Tests.Visual;
using osu.Game.Users;
namespace osu.Game.Tests.Beatmaps
{
public abstract class HitObjectSampleTest : PlayerTestScene
{
protected abstract IResourceStore<byte[]> Resources { get; }
private readonly SkinInfo userSkinInfo = new SkinInfo();
private readonly BeatmapInfo beatmapInfo = new BeatmapInfo
{
BeatmapSet = new BeatmapSetInfo(),
Metadata = new BeatmapMetadata
{
Author = User.SYSTEM_USER
}
};
private readonly TestResourceStore userSkinResourceStore = new TestResourceStore();
private readonly TestResourceStore beatmapSkinResourceStore = new TestResourceStore();
private SkinSourceDependencyContainer dependencies;
private IBeatmap currentTestBeatmap;
protected sealed override bool HasCustomSteps => true;
protected sealed override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> new DependencyContainer(dependencies = new SkinSourceDependencyContainer(base.CreateChildDependencies(parent)));
protected sealed override IBeatmap CreateBeatmap(RulesetInfo ruleset) => currentTestBeatmap;
protected sealed override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
=> new TestWorkingBeatmap(beatmapInfo, beatmapSkinResourceStore, beatmap, storyboard, Clock, Audio);
protected void CreateTestWithBeatmap(string filename)
{
CreateTest(() =>
{
AddStep("clear performed lookups", () =>
{
userSkinResourceStore.PerformedLookups.Clear();
beatmapSkinResourceStore.PerformedLookups.Clear();
});
AddStep($"load {filename}", () =>
{
using (var reader = new LineBufferedReader(Resources.GetStream($"Resources/SampleLookups/{filename}")))
currentTestBeatmap = Decoder.GetDecoder<Beatmap>(reader).Decode(reader);
});
});
}
protected void SetupSkins(string beatmapFile, string userFile)
{
AddStep("setup skins", () =>
{
userSkinInfo.Files = new List<SkinFileInfo>
{
new SkinFileInfo
{
Filename = userFile,
FileInfo = new IO.FileInfo { Hash = userFile }
}
};
beatmapInfo.BeatmapSet.Files = new List<BeatmapSetFileInfo>
{
new BeatmapSetFileInfo
{
Filename = beatmapFile,
FileInfo = new IO.FileInfo { Hash = beatmapFile }
}
};
// Need to refresh the cached skin source to refresh the skin resource store.
dependencies.SkinSource = new SkinProvidingContainer(new LegacySkin(userSkinInfo, userSkinResourceStore, Audio));
});
}
protected void AssertBeatmapLookup(string name) => AddAssert($"\"{name}\" looked up from beatmap skin",
() => !userSkinResourceStore.PerformedLookups.Contains(name) && beatmapSkinResourceStore.PerformedLookups.Contains(name));
protected void AssertUserLookup(string name) => AddAssert($"\"{name}\" looked up from user skin",
() => !beatmapSkinResourceStore.PerformedLookups.Contains(name) && userSkinResourceStore.PerformedLookups.Contains(name));
private class SkinSourceDependencyContainer : IReadOnlyDependencyContainer
{
public ISkinSource SkinSource;
private readonly IReadOnlyDependencyContainer fallback;
public SkinSourceDependencyContainer(IReadOnlyDependencyContainer fallback)
{
this.fallback = fallback;
}
public object Get(Type type)
{
if (type == typeof(ISkinSource))
return SkinSource;
return fallback.Get(type);
}
public object Get(Type type, CacheInfo info)
{
if (type == typeof(ISkinSource))
return SkinSource;
return fallback.Get(type, info);
}
public void Inject<T>(T instance) where T : class
{
// Never used directly
}
}
private class TestResourceStore : IResourceStore<byte[]>
{
public readonly List<string> PerformedLookups = new List<string>();
public byte[] Get(string name)
{
markLookup(name);
return Array.Empty<byte>();
}
public Task<byte[]> GetAsync(string name)
{
markLookup(name);
return Task.FromResult(Array.Empty<byte>());
}
public Stream GetStream(string name)
{
markLookup(name);
return new MemoryStream();
}
private void markLookup(string name) => PerformedLookups.Add(name.Substring(name.LastIndexOf(Path.DirectorySeparatorChar) + 1));
public IEnumerable<string> GetAvailableResources() => Enumerable.Empty<string>();
public void Dispose()
{
}
}
private class TestWorkingBeatmap : ClockBackedTestWorkingBeatmap
{
private readonly BeatmapInfo skinBeatmapInfo;
private readonly IResourceStore<byte[]> resourceStore;
public TestWorkingBeatmap(BeatmapInfo skinBeatmapInfo, IResourceStore<byte[]> resourceStore, IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio,
double length = 60000)
: base(beatmap, storyboard, referenceClock, audio, length)
{
this.skinBeatmapInfo = skinBeatmapInfo;
this.resourceStore = resourceStore;
}
protected override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, AudioManager);
}
}
}