2019-01-24 16:43:03 +08:00
// 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.
2018-04-13 17:19:50 +08:00
using System ;
using System.Linq ;
using NUnit.Framework ;
2019-03-25 00:02:36 +08:00
using osu.Framework.Allocation ;
2019-02-21 18:04:31 +08:00
using osu.Framework.Bindables ;
2020-03-11 09:18:41 +08:00
using osu.Framework.Extensions.Color4Extensions ;
2019-03-25 00:02:36 +08:00
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
using osu.Game.Graphics ;
2021-11-04 17:02:44 +08:00
using osu.Game.Online.API.Requests.Responses ;
2019-03-25 00:02:36 +08:00
using osu.Game.Online.Chat ;
using osu.Game.Overlays.Chat ;
using osuTK.Graphics ;
2018-04-13 17:19:50 +08:00
2019-03-25 00:02:36 +08:00
namespace osu.Game.Tests.Visual.Online
2018-04-13 17:19:50 +08:00
{
[TestFixture]
2022-11-24 13:32:20 +08:00
public partial class TestSceneChatLink : OsuTestScene
2018-04-13 17:19:50 +08:00
{
private readonly TestChatLineContainer textContainer ;
private Color4 linkColour ;
2019-05-15 03:37:25 +08:00
public TestSceneChatLink ( )
2018-04-13 17:19:50 +08:00
{
Add ( textContainer = new TestChatLineContainer
{
Padding = new MarginPadding { Left = 20 , Right = 20 } ,
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
Direction = FillDirection . Vertical ,
} ) ;
}
[BackgroundDependencyLoader]
private void load ( OsuColour colours )
{
linkColour = colours . Blue ;
2018-04-14 19:31:03 +08:00
2022-11-04 17:51:00 +08:00
var chatManager = new ChannelManager ( API ) ;
2019-01-07 17:50:27 +08:00
BindableList < Channel > availableChannels = ( BindableList < Channel > ) chatManager . AvailableChannels ;
2019-02-28 12:31:40 +08:00
availableChannels . Add ( new Channel { Name = "#english" } ) ;
2018-11-22 04:44:56 +08:00
availableChannels . Add ( new Channel { Name = "#japanese" } ) ;
2018-06-17 21:08:13 +08:00
Dependencies . Cache ( chatManager ) ;
2022-10-28 17:08:08 +08:00
Add ( chatManager ) ;
2018-04-13 17:19:50 +08:00
}
2022-01-11 16:42:02 +08:00
[SetUp]
public void Setup ( ) = > Schedule ( ( ) = >
2018-04-13 17:19:50 +08:00
{
2022-01-11 16:42:02 +08:00
textContainer . Clear ( ) ;
} ) ;
2018-04-13 17:19:50 +08:00
2023-12-01 06:34:43 +08:00
[TestCase("test!")]
[TestCase("dev.ppy.sh!")]
[TestCase("https://dev.ppy.sh!", LinkAction.External)]
[TestCase("http://dev.ppy.sh!", LinkAction.External)]
[TestCase("forgothttps://dev.ppy.sh!", LinkAction.External)]
[TestCase("forgothttp://dev.ppy.sh!", LinkAction.External)]
2023-12-01 07:45:35 +08:00
[TestCase("00:12:345 - Test?", LinkAction.OpenEditorTimestamp)]
2023-12-01 06:34:43 +08:00
[TestCase("00:12:345 (1,2) - Test?", LinkAction.OpenEditorTimestamp)]
2023-12-01 07:45:35 +08:00
[TestCase($"{OsuGameBase.OSU_PROTOCOL}edit/00:12:345 - Test?", LinkAction.OpenEditorTimestamp)]
2023-12-01 06:34:43 +08:00
[TestCase("Wiki link for tasty [[Performance Points] ] ", LinkAction.OpenWiki)]
[TestCase("(osu forums)[https://dev.ppy.sh/forum] ( old link format ) ", LinkAction.External)]
[TestCase("[https://dev.ppy.sh/home New site] ( new link format ) ", LinkAction.External)]
[TestCase("[osu forums] ( https : //dev.ppy.sh/forum) (new link format 2)", LinkAction.External)]
[TestCase("[https://dev.ppy.sh/home This is only a link to the new osu webpage but this is supposed to test word wrap.] ", LinkAction.External)]
[TestCase("Let's (try)[https://dev.ppy.sh/home] [ https : //dev.ppy.sh/b/252238 multiple links] https://dev.ppy.sh/home", LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External)]
[TestCase("[https://dev.ppy.sh/home New link format with escaped [and \\[ paired] braces ] ", LinkAction.External)]
[TestCase("[Markdown link format with escaped [and \\[ paired] braces ] ( https : //dev.ppy.sh/home)", LinkAction.External)]
[TestCase("(Old link format with escaped (and \\( paired) parentheses)[https://dev.ppy.sh/home] and [ [ also a rogue wiki link ] ] ", LinkAction.External, LinkAction.OpenWiki)]
[TestCase("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).")] // note that there's 0 links here (they get removed if a channel is not found)
[TestCase("Join my multiplayer game osump://12346.", LinkAction.JoinMultiplayerMatch)]
[TestCase("Join my multiplayer gameosump://12346.", LinkAction.JoinMultiplayerMatch)]
[TestCase("Join my [multiplayer game] ( osump : //12346).", LinkAction.JoinMultiplayerMatch)]
[TestCase($"Join my [#english] ( { OsuGameBase . OSU_PROTOCOL } chan / # english ) . ", LinkAction.OpenChannel)]
[TestCase($"Join my {OsuGameBase.OSU_PROTOCOL}chan/#english.", LinkAction.OpenChannel)]
[TestCase($"Join my{OsuGameBase.OSU_PROTOCOL}chan/#english.", LinkAction.OpenChannel)]
[TestCase("Join my #english or #japanese channels.", LinkAction.OpenChannel, LinkAction.OpenChannel)]
[TestCase("Join my #english or #nonexistent #hashtag channels.", LinkAction.OpenChannel)]
[TestCase("Hello world\uD83D\uDE12(<--This is an emoji). There are more:\uD83D\uDE10\uD83D\uDE00,\uD83D\uDE20")]
public void TestLinksGeneral ( string text , params LinkAction [ ] actions )
2018-04-13 17:19:50 +08:00
{
2023-12-01 06:34:43 +08:00
addMessageWithChecks ( text , expectedActions : actions ) ;
2023-12-01 06:25:28 +08:00
}
2022-01-11 16:42:02 +08:00
2023-12-01 06:29:22 +08:00
[TestCase("is now listening to [https://dev.ppy.sh/s/93523 IMAGE -MATERIAL- <Version 0>] ", true, false, LinkAction.OpenBeatmapSet)]
[TestCase("is now playing [https://dev.ppy.sh/b/252238 IMAGE -MATERIAL- <Version 0>] ", true, false, LinkAction.OpenBeatmap)]
[TestCase("I am important!", false, true)]
[TestCase("feels important", true, true)]
[TestCase("likes to post this [https://dev.ppy.sh/home link] . ", true, true, LinkAction.External)]
public void TestActionAndImportantLinks ( string text , bool isAction , bool isImportant , params LinkAction [ ] expectedActions )
{
addMessageWithChecks ( text , isAction , isImportant , expectedActions ) ;
}
2023-12-01 06:25:28 +08:00
private void addMessageWithChecks ( string text , bool isAction = false , bool isImportant = false , params LinkAction [ ] expectedActions )
{
2023-12-01 07:37:16 +08:00
ChatLine newLine = null ! ;
2022-01-11 16:42:02 +08:00
2023-12-01 06:25:28 +08:00
AddStep ( "add message" , ( ) = >
{
newLine = new ChatLine ( new DummyMessage ( text , isAction , isImportant ) ) ;
textContainer . Add ( newLine ) ;
} ) ;
2022-01-11 16:42:02 +08:00
2023-12-01 06:35:10 +08:00
AddAssert ( "msg has the right action" , ( ) = > newLine . Message . Links . Select ( l = > l . Action ) , ( ) = > Is . EqualTo ( expectedActions ) ) ;
//AddAssert("msg is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic());
2023-12-01 06:25:28 +08:00
AddAssert ( $"msg shows {expectedActions.Length} link(s)" , isShowingLinks ) ;
2022-01-11 16:42:02 +08:00
2023-12-01 06:25:28 +08:00
//bool isItalic() => newLine.ContentFlow.Where(d => d is OsuSpriteText).Cast<OsuSpriteText>().All(sprite => sprite.Font.Italics);
2022-01-11 16:42:02 +08:00
2023-12-01 06:25:28 +08:00
bool isShowingLinks ( )
{
bool hasBackground = ! string . IsNullOrEmpty ( newLine . Message . Sender . Colour ) ;
2022-01-11 16:42:02 +08:00
2023-12-01 06:25:28 +08:00
Color4 textColour = isAction & & hasBackground ? Color4Extensions . FromHex ( newLine . Message . Sender . Colour ) : Color4 . White ;
2022-01-11 16:42:02 +08:00
2023-12-01 06:25:28 +08:00
var linkCompilers = newLine . DrawableContentFlow . Where ( d = > d is DrawableLinkCompiler ) . ToList ( ) ;
var linkSprites = linkCompilers . SelectMany ( comp = > ( ( DrawableLinkCompiler ) comp ) . Parts ) ;
2022-01-11 16:42:02 +08:00
2023-12-01 06:25:28 +08:00
return linkSprites . All ( d = > d . Colour = = linkColour )
2023-12-01 07:29:37 +08:00
& & newLine . DrawableContentFlow . Except ( linkSprites . Concat ( linkCompilers ) ) . All ( d = > d . Colour = = textColour )
& & linkCompilers . Count = = expectedActions . Length ;
2022-01-11 16:42:02 +08:00
}
2018-04-13 17:19:50 +08:00
}
2022-01-11 16:42:02 +08:00
[Test]
public void TestEcho ( )
2018-04-13 17:19:50 +08:00
{
2022-01-11 16:42:02 +08:00
int messageIndex = 0 ;
2018-04-13 17:19:50 +08:00
addEchoWithWait ( "sent!" , "received!" ) ;
2021-02-12 14:29:21 +08:00
addEchoWithWait ( "https://dev.ppy.sh/home" , null , 500 ) ;
addEchoWithWait ( "[https://dev.ppy.sh/forum let's try multiple words too!]" ) ;
addEchoWithWait ( "(long loading times! clickable while loading?)[https://dev.ppy.sh/home]" , null , 5000 ) ;
2018-04-13 17:19:50 +08:00
2023-12-01 07:37:16 +08:00
void addEchoWithWait ( string text , string? completeText = null , double delay = 250 )
2018-04-13 17:19:50 +08:00
{
2022-01-11 16:42:02 +08:00
int index = messageIndex + + ;
2018-04-13 17:19:50 +08:00
2022-01-11 16:42:02 +08:00
AddStep ( $"send msg #{index} after {delay}ms" , ( ) = >
2018-04-13 17:19:50 +08:00
{
2022-01-11 16:42:02 +08:00
ChatLine newLine = new ChatLine ( new DummyEchoMessage ( text ) ) ;
2018-04-13 17:19:50 +08:00
textContainer . Add ( newLine ) ;
Scheduler . AddDelayed ( ( ) = > newLine . Message = new DummyMessage ( completeText ? ? text ) , delay ) ;
} ) ;
2022-01-11 16:42:02 +08:00
AddUntilStep ( $"wait for msg #{index}" , ( ) = > textContainer . All ( line = > line . Message is DummyMessage ) ) ;
2018-04-13 17:19:50 +08:00
}
}
private class DummyEchoMessage : LocalEchoMessage
{
public DummyEchoMessage ( string text )
{
Content = text ;
Timestamp = DateTimeOffset . Now ;
Sender = DummyMessage . TEST_SENDER ;
}
}
private class DummyMessage : Message
{
private static long messageCounter ;
2021-11-04 17:02:44 +08:00
internal static readonly APIUser TEST_SENDER = new APIUser
2018-04-13 17:19:50 +08:00
{
Username = @"Somebody" ,
Id = 1 ,
} ;
public DummyMessage ( string text , bool isAction = false , bool isImportant = false , int number = 0 )
: base ( messageCounter + + )
{
Content = text ;
IsAction = isAction ;
2021-11-04 17:02:44 +08:00
Sender = new APIUser
2018-04-13 17:19:50 +08:00
{
Username = $"User {number}" ,
Id = number ,
Colour = isImportant ? "#250cc9" : null ,
} ;
}
}
2022-11-24 13:32:20 +08:00
private partial class TestChatLineContainer : FillFlowContainer < ChatLine >
2018-04-13 17:19:50 +08:00
{
protected override int Compare ( Drawable x , Drawable y )
{
var xC = ( ChatLine ) x ;
var yC = ( ChatLine ) y ;
return xC . Message . CompareTo ( yC . Message ) ;
}
}
}
}