Merge branch 'master' into chat-mention

This commit is contained in:
Dean Herbert
2021-06-11 20:03:44 +09:00
committed by GitHub
185 changed files with 2515 additions and 944 deletions

View File

@ -123,6 +123,8 @@ namespace osu.Game.Tests.Gameplay
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => null;
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{
switch (lookup)

View File

@ -33,10 +33,11 @@ namespace osu.Game.Tests.NonVisual.Filtering
* outside of the range.
*/
[Test]
public void TestApplyStarQueries()
[TestCase("star")]
[TestCase("stars")]
public void TestApplyStarQueries(string variant)
{
const string query = "stars<4 easy";
string query = $"{variant}<4 easy";
var filterCriteria = new FilterCriteria();
FilterQueryParser.ApplyQueries(filterCriteria, query);
Assert.AreEqual("easy", filterCriteria.SearchText.Trim());

View File

@ -61,6 +61,7 @@ namespace osu.Game.Tests.NonVisual.Skinning
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException();
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => null;
}
private class TestAnimationTimeReference : IAnimationTimeReference

View File

@ -1,2 +1,2 @@
[General]
Version: 1.0
// no version specified means v1

View File

@ -0,0 +1,116 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.OpenGL.Textures;
using osu.Framework.Graphics.Textures;
using osu.Framework.Testing;
using osu.Game.Audio;
using osu.Game.Configuration;
using osu.Game.Rulesets.Osu;
using osu.Game.Skinning;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
namespace osu.Game.Tests.Skins
{
[TestFixture]
[HeadlessTest]
public class TestSceneBeatmapSkinLookupDisables : OsuTestScene
{
private UserSkinSource userSource;
private BeatmapSkinSource beatmapSource;
private SkinRequester requester;
[Resolved]
private OsuConfigManager config { get; set; }
[SetUp]
public void SetUp() => Schedule(() =>
{
Add(new SkinProvidingContainer(userSource = new UserSkinSource())
.WithChild(new BeatmapSkinProvidingContainer(beatmapSource = new BeatmapSkinSource())
.WithChild(requester = new SkinRequester())));
});
[TestCase(false)]
[TestCase(true)]
public void TestDrawableLookup(bool allowBeatmapLookups)
{
AddStep($"Set beatmap skin enabled to {allowBeatmapLookups}", () => config.SetValue(OsuSetting.BeatmapSkins, allowBeatmapLookups));
string expected = allowBeatmapLookups ? "beatmap" : "user";
AddAssert($"Check lookup is from {expected}", () => requester.GetDrawableComponent(new TestSkinComponent())?.Name == expected);
}
[TestCase(false)]
[TestCase(true)]
public void TestProviderLookup(bool allowBeatmapLookups)
{
AddStep($"Set beatmap skin enabled to {allowBeatmapLookups}", () => config.SetValue(OsuSetting.BeatmapSkins, allowBeatmapLookups));
ISkin expected() => allowBeatmapLookups ? (ISkin)beatmapSource : userSource;
AddAssert("Check lookup is from correct source", () => requester.FindProvider(s => s.GetDrawableComponent(new TestSkinComponent()) != null) == expected());
}
public class UserSkinSource : LegacySkin
{
public UserSkinSource()
: base(new SkinInfo(), null, null, string.Empty)
{
}
public override Drawable GetDrawableComponent(ISkinComponent component)
{
return new Container { Name = "user" };
}
}
public class BeatmapSkinSource : LegacyBeatmapSkin
{
public BeatmapSkinSource()
: base(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, null, null)
{
}
public override Drawable GetDrawableComponent(ISkinComponent component)
{
return new Container { Name = "beatmap" };
}
}
public class SkinRequester : Drawable, ISkin
{
private ISkinSource skin;
[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
this.skin = skin;
}
public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component);
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT);
public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => skin.FindProvider(lookupFunction);
}
private class TestSkinComponent : ISkinComponent
{
public string LookupName => string.Empty;
}
}
}

View File

@ -1,6 +1,7 @@
// 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;
@ -222,6 +223,8 @@ namespace osu.Game.Tests.Skins
public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => skin.FindProvider(lookupFunction);
}
}
}

View File

@ -0,0 +1,133 @@
// 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.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Online.API;
using osu.Game.Screens;
using osu.Game.Screens.Backgrounds;
using osu.Game.Skinning;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Background
{
[TestFixture]
public class TestSceneBackgroundScreenDefault : OsuTestScene
{
private BackgroundScreenStack stack;
private BackgroundScreenDefault screen;
private Graphics.Backgrounds.Background getCurrentBackground() => screen.ChildrenOfType<Graphics.Backgrounds.Background>().FirstOrDefault();
[Resolved]
private SkinManager skins { get; set; }
[Resolved]
private OsuConfigManager config { get; set; }
[SetUpSteps]
public void SetUpSteps()
{
AddStep("create background stack", () => Child = stack = new BackgroundScreenStack());
AddStep("push default screen", () => stack.Push(screen = new BackgroundScreenDefault(false)));
AddUntilStep("wait for screen to load", () => screen.IsCurrentScreen());
}
[Test]
public void TestBackgroundTypeSwitch()
{
setSupporter(true);
setSourceMode(BackgroundSource.Beatmap);
AddUntilStep("is beatmap background", () => getCurrentBackground() is BeatmapBackground);
setSourceMode(BackgroundSource.BeatmapWithStoryboard);
AddUntilStep("is storyboard background", () => getCurrentBackground() is BeatmapBackgroundWithStoryboard);
setSourceMode(BackgroundSource.Skin);
AddUntilStep("is default background", () => getCurrentBackground().GetType() == typeof(Graphics.Backgrounds.Background));
setCustomSkin();
AddUntilStep("is skin background", () => getCurrentBackground() is SkinBackground);
}
[Test]
public void TestTogglingSupporterTogglesBeatmapBackground()
{
setSourceMode(BackgroundSource.Beatmap);
setSupporter(true);
AddUntilStep("is beatmap background", () => getCurrentBackground() is BeatmapBackground);
setSupporter(false);
AddUntilStep("is default background", () => !(getCurrentBackground() is BeatmapBackground));
setSupporter(true);
AddUntilStep("is beatmap background", () => getCurrentBackground() is BeatmapBackground);
}
[TestCase(BackgroundSource.Beatmap, typeof(BeatmapBackground))]
[TestCase(BackgroundSource.BeatmapWithStoryboard, typeof(BeatmapBackgroundWithStoryboard))]
[TestCase(BackgroundSource.Skin, typeof(SkinBackground))]
public void TestBackgroundDoesntReloadOnNoChange(BackgroundSource source, Type backgroundType)
{
Graphics.Backgrounds.Background last = null;
setSourceMode(source);
setSupporter(true);
if (source == BackgroundSource.Skin)
setCustomSkin();
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == backgroundType);
AddAssert("next doesn't load new background", () => screen.Next() == false);
// doesn't really need to be checked but might as well.
AddWaitStep("wait a bit", 5);
AddUntilStep("ensure same background instance", () => last == getCurrentBackground());
}
[Test]
public void TestBackgroundCyclingOnDefaultSkin([Values] bool supporter)
{
Graphics.Backgrounds.Background last = null;
setSourceMode(BackgroundSource.Skin);
setSupporter(supporter);
setDefaultSkin();
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == typeof(Graphics.Backgrounds.Background));
AddAssert("next cycles background", () => screen.Next());
// doesn't really need to be checked but might as well.
AddWaitStep("wait a bit", 5);
AddUntilStep("ensure different background instance", () => last != getCurrentBackground());
}
private void setSourceMode(BackgroundSource source) =>
AddStep($"set background mode to {source}", () => config.SetValue(OsuSetting.MenuBackgroundSource, source));
private void setSupporter(bool isSupporter) =>
AddStep($"set supporter {isSupporter}", () => ((DummyAPIAccess)API).LocalUser.Value = new User
{
IsSupporter = isSupporter,
Id = API.LocalUser.Value.Id + 1,
});
private void setCustomSkin()
{
// feign a skin switch. this doesn't do anything except force CurrentSkin to become a LegacySkin.
AddStep("set custom skin", () => skins.CurrentSkinInfo.Value = new SkinInfo { ID = 5 });
}
private void setDefaultSkin() => AddStep("set default skin", () => skins.CurrentSkinInfo.SetDefault());
[TearDownSteps]
public void TearDown() => setDefaultSkin();
}
}

View File

@ -0,0 +1,144 @@
// 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.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Setup;
namespace osu.Game.Tests.Visual.Editing
{
public class TestSceneMetadataSection : OsuTestScene
{
[Cached]
private EditorBeatmap editorBeatmap = new EditorBeatmap(new Beatmap());
private TestMetadataSection metadataSection;
[Test]
public void TestMinimalMetadata()
{
AddStep("set metadata", () =>
{
editorBeatmap.Metadata.Artist = "Example Artist";
editorBeatmap.Metadata.ArtistUnicode = null;
editorBeatmap.Metadata.Title = "Example Title";
editorBeatmap.Metadata.TitleUnicode = null;
});
createSection();
assertArtist("Example Artist");
assertRomanisedArtist("Example Artist", false);
assertTitle("Example Title");
assertRomanisedTitle("Example Title", false);
}
[Test]
public void TestInitialisationFromNonRomanisedVariant()
{
AddStep("set metadata", () =>
{
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
editorBeatmap.Metadata.Artist = null;
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
editorBeatmap.Metadata.Title = null;
});
createSection();
assertArtist("*なみりん");
assertRomanisedArtist(string.Empty, true);
assertTitle("コイシテイク・プラネット");
assertRomanisedTitle(string.Empty, true);
}
[Test]
public void TestInitialisationPreservesOriginalValues()
{
AddStep("set metadata", () =>
{
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
editorBeatmap.Metadata.Artist = "*namirin";
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
editorBeatmap.Metadata.Title = "Koishiteiku Planet";
});
createSection();
assertArtist("*なみりん");
assertRomanisedArtist("*namirin", true);
assertTitle("コイシテイク・プラネット");
assertRomanisedTitle("Koishiteiku Planet", true);
}
[Test]
public void TestValueTransfer()
{
AddStep("set metadata", () =>
{
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
editorBeatmap.Metadata.Artist = null;
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
editorBeatmap.Metadata.Title = null;
});
createSection();
AddStep("set romanised artist name", () => metadataSection.ArtistTextBox.Current.Value = "*namirin");
assertArtist("*namirin");
assertRomanisedArtist("*namirin", false);
AddStep("set native artist name", () => metadataSection.ArtistTextBox.Current.Value = "*なみりん");
assertArtist("*なみりん");
assertRomanisedArtist("*namirin", true);
AddStep("set romanised title", () => metadataSection.TitleTextBox.Current.Value = "Hitokoto no kyori");
assertTitle("Hitokoto no kyori");
assertRomanisedTitle("Hitokoto no kyori", false);
AddStep("set native title", () => metadataSection.TitleTextBox.Current.Value = "ヒトコトの距離");
assertTitle("ヒトコトの距離");
assertRomanisedTitle("Hitokoto no kyori", true);
}
private void createSection()
=> AddStep("create metadata section", () => Child = metadataSection = new TestMetadataSection());
private void assertArtist(string expected)
=> AddAssert($"artist is {expected}", () => metadataSection.ArtistTextBox.Current.Value == expected);
private void assertRomanisedArtist(string expected, bool editable)
{
AddAssert($"romanised artist is {expected}", () => metadataSection.RomanisedArtistTextBox.Current.Value == expected);
AddAssert($"romanised artist is {(editable ? "" : "not ")}editable", () => metadataSection.RomanisedArtistTextBox.ReadOnly == !editable);
}
private void assertTitle(string expected)
=> AddAssert($"title is {expected}", () => metadataSection.TitleTextBox.Current.Value == expected);
private void assertRomanisedTitle(string expected, bool editable)
{
AddAssert($"romanised title is {expected}", () => metadataSection.RomanisedTitleTextBox.Current.Value == expected);
AddAssert($"romanised title is {(editable ? "" : "not ")}editable", () => metadataSection.RomanisedTitleTextBox.ReadOnly == !editable);
}
private class TestMetadataSection : MetadataSection
{
public new LabelledTextBox ArtistTextBox => base.ArtistTextBox;
public new LabelledTextBox RomanisedArtistTextBox => base.RomanisedArtistTextBox;
public new LabelledTextBox TitleTextBox => base.TitleTextBox;
public new LabelledTextBox RomanisedTitleTextBox => base.RomanisedTitleTextBox;
}
}
}

View File

@ -4,14 +4,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Framework.Threading;
using osu.Framework.Utils;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mods;
@ -29,15 +30,22 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneHitErrorMeter : OsuTestScene
{
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
[Cached(typeof(ScoreProcessor))]
private TestScoreProcessor scoreProcessor = new TestScoreProcessor();
[Cached(typeof(DrawableRuleset))]
private TestDrawableRuleset drawableRuleset = new TestDrawableRuleset();
public TestSceneHitErrorMeter()
[SetUpSteps]
public void SetUp()
{
recreateDisplay(new OsuHitWindows(), 5);
AddStep("reset score processor", () => scoreProcessor.Reset());
}
[Test]
public void TestBasic()
{
AddStep("create display", () => recreateDisplay(new OsuHitWindows(), 5));
AddRepeatStep("New random judgement", () => newJudgement(), 40);
@ -45,12 +53,11 @@ namespace osu.Game.Tests.Visual.Gameplay
AddRepeatStep("New max positive", () => newJudgement(drawableRuleset.HitWindows.WindowFor(HitResult.Meh)), 20);
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
ScheduledDelegate del = null;
AddStep("Judgement barrage", () =>
{
int runCount = 0;
ScheduledDelegate del = null;
del = Scheduler.AddDelayed(() =>
{
newJudgement(runCount++ / 10f);
@ -60,6 +67,7 @@ namespace osu.Game.Tests.Visual.Gameplay
del?.Cancel();
}, 10, true);
});
AddUntilStep("wait for barrage", () => del.Cancelled);
}
[Test]
@ -84,10 +92,49 @@ namespace osu.Game.Tests.Visual.Gameplay
}
[Test]
public void TestCatch()
public void TestEmpty()
{
AddStep("OD 1", () => recreateDisplay(new CatchHitWindows(), 1));
AddStep("OD 10", () => recreateDisplay(new CatchHitWindows(), 10));
AddStep("empty windows", () => recreateDisplay(HitWindows.Empty, 5));
AddStep("hit", () => newJudgement());
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
AddAssert("circle added", () =>
this.ChildrenOfType<ColourHitErrorMeter>().All(
meter => meter.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Count() == 1));
AddStep("miss", () => newJudgement(50, HitResult.Miss));
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
AddAssert("circle added", () =>
this.ChildrenOfType<ColourHitErrorMeter>().All(
meter => meter.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Count() == 2));
}
[Test]
public void TestBonus()
{
AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1));
AddStep("small bonus", () => newJudgement(result: HitResult.SmallBonus));
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
AddStep("large bonus", () => newJudgement(result: HitResult.LargeBonus));
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
}
[Test]
public void TestIgnore()
{
AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1));
AddStep("ignore hit", () => newJudgement(result: HitResult.IgnoreHit));
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
AddStep("ignore miss", () => newJudgement(result: HitResult.IgnoreMiss));
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
}
private void recreateDisplay(HitWindows hitWindows, float overallDifficulty)
@ -154,12 +201,12 @@ namespace osu.Game.Tests.Visual.Gameplay
});
}
private void newJudgement(double offset = 0)
private void newJudgement(double offset = 0, HitResult result = HitResult.Perfect)
{
scoreProcessor.ApplyResult(new JudgementResult(new HitCircle { HitWindows = drawableRuleset.HitWindows }, new Judgement())
{
TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset,
Type = HitResult.Perfect,
Type = result,
});
}
@ -199,5 +246,10 @@ namespace osu.Game.Tests.Visual.Gameplay
public override void CancelResume() => throw new NotImplementedException();
}
private class TestScoreProcessor : ScoreProcessor
{
public void Reset() => base.Reset(false);
}
}
}

View File

@ -42,9 +42,9 @@ namespace osu.Game.Tests.Visual.Gameplay
Spacing = new Vector2(10),
Children = new[]
{
new ExposedSkinnableDrawable("default", _ => new DefaultBox(), _ => true),
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true),
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true, ConfineMode.NoScaling)
new ExposedSkinnableDrawable("default", _ => new DefaultBox()),
new ExposedSkinnableDrawable("available", _ => new DefaultBox()),
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), ConfineMode.NoScaling)
}
},
};
@ -73,9 +73,9 @@ namespace osu.Game.Tests.Visual.Gameplay
Spacing = new Vector2(10),
Children = new[]
{
new ExposedSkinnableDrawable("default", _ => new DefaultBox(), _ => true),
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true, ConfineMode.ScaleToFit),
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), _ => true, ConfineMode.NoScaling)
new ExposedSkinnableDrawable("default", _ => new DefaultBox()),
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), ConfineMode.ScaleToFit),
new ExposedSkinnableDrawable("available", _ => new DefaultBox(), ConfineMode.NoScaling)
}
},
};
@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.Gameplay
Child = new SkinProvidingContainer(secondarySource)
{
RelativeSizeAxes = Axes.Both,
Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)
Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"))
}
};
});
@ -129,7 +129,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
});
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)));
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"))));
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1);
}
@ -152,7 +152,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
});
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)));
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"))));
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
AddStep("disable", () => target.Disable());
AddAssert("consumer using base source", () => consumer.Drawable is BaseSourceBox);
@ -180,9 +180,8 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public new Drawable Drawable => base.Drawable;
public ExposedSkinnableDrawable(string name, Func<ISkinComponent, Drawable> defaultImplementation, Func<ISkinSource, bool> allowFallback = null,
ConfineMode confineMode = ConfineMode.ScaleToFit)
: base(new TestSkinComponent(name), defaultImplementation, allowFallback, confineMode)
public ExposedSkinnableDrawable(string name, Func<ISkinComponent, Drawable> defaultImplementation, ConfineMode confineMode = ConfineMode.ScaleToFit)
: base(new TestSkinComponent(name), defaultImplementation, confineMode)
{
}
}
@ -250,14 +249,14 @@ namespace osu.Game.Tests.Visual.Gameplay
public new Drawable Drawable => base.Drawable;
public int SkinChangedCount { get; private set; }
public SkinConsumer(string name, Func<ISkinComponent, Drawable> defaultImplementation, Func<ISkinSource, bool> allowFallback = null)
: base(new TestSkinComponent(name), defaultImplementation, allowFallback)
public SkinConsumer(string name, Func<ISkinComponent, Drawable> defaultImplementation)
: base(new TestSkinComponent(name), defaultImplementation)
{
}
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
protected override void SkinChanged(ISkinSource skin)
{
base.SkinChanged(skin, allowFallback);
base.SkinChanged(skin);
SkinChangedCount++;
}
}
@ -301,6 +300,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => throw new NotImplementedException();
}
private class SecondarySource : ISkin
@ -312,6 +313,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => throw new NotImplementedException();
}
[Cached(typeof(ISkinSource))]
@ -325,6 +328,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => throw new NotImplementedException();
public event Action SourceChanged
{
add { }

View File

@ -29,14 +29,13 @@ namespace osu.Game.Tests.Visual.Gameplay
{
AddStep("setup hierarchy", () =>
{
Children = new Drawable[]
Child = skinSource = new TestSkinSourceContainer
{
skinSource = new TestSkinSourceContainer
{
RelativeSizeAxes = Axes.Both,
Child = skinnableSound = new PausableSkinnableSound(new SampleInfo("Gameplay/normal-sliderslide"))
},
RelativeSizeAxes = Axes.Both,
};
// has to be added after the hierarchy above else the `ISkinSource` dependency won't be cached.
skinSource.Add(skinnableSound = new PausableSkinnableSound(new SampleInfo("Gameplay/normal-sliderslide")));
});
}
@ -147,6 +146,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => source?.GetTexture(componentName, wrapModeS, wrapModeT);
public ISample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => source?.GetConfig<TLookup, TValue>(lookup);
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => source?.FindProvider(lookupFunction);
public void TriggerSourceChanged()
{

View File

@ -9,16 +9,19 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Toolbar;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Options;
using osu.Game.Tests.Beatmaps.IO;
using osu.Game.Tests.Visual.Multiplayer;
using osuTK;
using osuTK.Input;
@ -152,6 +155,14 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for track", () => !Game.MusicController.CurrentTrack.IsDummyDevice && Game.MusicController.IsPlaying);
}
[Test]
public void TestPushSongSelectAndPressBackButtonImmediately()
{
AddStep("push song select", () => Game.ScreenStack.Push(new TestPlaySongSelect()));
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
AddWaitStep("wait two frames", 2);
}
[Test]
public void TestExitSongSelectWithClick()
{
@ -298,6 +309,18 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("Toolbar is hidden", () => Game.Toolbar.State.Value == Visibility.Hidden);
}
[Test]
public void TestPushMatchSubScreenAndPressBackButtonImmediately()
{
TestMultiplayer multiplayer = null;
PushAndConfirm(() => multiplayer = new TestMultiplayer());
AddStep("open room", () => multiplayer.OpenNewRoom());
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
AddWaitStep("wait two frames", 2);
}
private void pushEscape() =>
AddStep("Press escape", () => InputManager.Key(Key.Escape));
@ -322,5 +345,18 @@ namespace osu.Game.Tests.Visual.Navigation
protected override bool DisplayStableImportPrompt => false;
}
private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
{
[Cached(typeof(MultiplayerClient))]
public readonly TestMultiplayerClient Client;
public TestMultiplayer()
{
Client = new TestMultiplayerClient((TestMultiplayerRoomManager)RoomManager);
}
protected override RoomManager CreateRoomManager() => new TestMultiplayerRoomManager();
}
}
}

View File

@ -143,6 +143,25 @@ Line after image";
});
}
[Test]
public void TestTableWithImageContent()
{
AddStep("Add Table", () =>
{
markdownContainer.DocumentUrl = "https://dev.ppy.sh";
markdownContainer.Text = @"
| Image | Name | Effect |
| :-: | :-: | :-- |
| ![](/wiki/Skinning/Interface/img/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. |
| ![](/wiki/Skinning/Interface/img/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. |
| ![](/wiki/Skinning/Interface/img/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. |
| ![](/wiki/Skinning/Interface/img/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. |
| ![](/wiki/Skinning/Interface/img/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. |
| ![](/wiki/Skinning/Interface/img/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. |
";
});
}
private class TestMarkdownContainer : WikiMarkdownContainer
{
public LinkInline Link;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,65 @@
// 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 Markdig.Parsers;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Graphics.Containers.Markdown;
using osu.Game.Overlays;
using osu.Game.Overlays.Wiki;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneWikiSidebar : OsuTestScene
{
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange);
[Cached]
private readonly OverlayScrollContainer scrollContainer = new OverlayScrollContainer();
private WikiSidebar sidebar;
[SetUp]
public void SetUp() => Schedule(() => Child = sidebar = new WikiSidebar());
[Test]
public void TestNoContent()
{
AddStep("No Content", () => { });
}
[Test]
public void TestOnlyMainTitle()
{
AddStep("Add TOC", () =>
{
for (var i = 0; i < 10; i++)
addTitle($"This is a very long title {i + 1}");
});
}
[Test]
public void TestWithSubtitle()
{
AddStep("Add TOC", () =>
{
for (var i = 0; i < 10; i++)
addTitle($"This is a very long title {i + 1}", i % 4 != 0);
});
}
private void addTitle(string text, bool subtitle = false)
{
var headingBlock = new HeadingBlock(new HeadingBlockParser())
{
Inline = new ContainerInline().AppendChild(new LiteralInline(text)),
Level = subtitle ? 3 : 2,
};
var heading = new OsuMarkdownHeading(headingBlock);
sidebar.AddEntry(headingBlock, heading);
}
}
}

View File

@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Ranking
}
}
},
new AccuracyCircle(score)
new AccuracyCircle(score, true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,

View File

@ -2,11 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterfaceV2;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
@ -21,6 +24,45 @@ namespace osu.Game.Tests.Visual.UserInterface
[TestCase(true)]
public void TestNonPadded(bool hasDescription) => createPaddedComponent(hasDescription, false);
[Test]
public void TestFixedWidth()
{
const float label_width = 200;
AddStep("create components", () => Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
new NonPaddedLabelledDrawable
{
Label = "short",
FixedLabelWidth = label_width
},
new NonPaddedLabelledDrawable
{
Label = "very very very very very very very very very very very long",
FixedLabelWidth = label_width
},
new PaddedLabelledDrawable
{
Label = "short",
FixedLabelWidth = label_width
},
new PaddedLabelledDrawable
{
Label = "very very very very very very very very very very very long",
FixedLabelWidth = label_width
}
}
});
AddStep("unset label width", () => this.ChildrenOfType<LabelledDrawable<Drawable>>().ForEach(d => d.FixedLabelWidth = null));
AddStep("reset label width", () => this.ChildrenOfType<LabelledDrawable<Drawable>>().ForEach(d => d.FixedLabelWidth = label_width));
}
private void createPaddedComponent(bool hasDescription = false, bool padded = true)
{
AddStep("create component", () =>