using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
-using OpenTween.Api;
+using OpenTween.Api.DataModel;
+using OpenTween.Models;
+using OpenTween.Setting;
using Xunit;
using Xunit.Extensions;
}
[Theory]
+ [InlineData("https://twitter.com/twitterapi/status/22634515958", true)]
+ [InlineData("http://twitter.com/twitterapi/status/22634515958", true)]
+ [InlineData("https://mobile.twitter.com/twitterapi/status/22634515958", true)]
+ [InlineData("http://mobile.twitter.com/twitterapi/status/22634515958", true)]
+ [InlineData("https://twitter.com/i/web/status/22634515958", false)]
+ [InlineData("https://twitter.com/imgazyobuzi/status/293333871171354624/photo/1", false)]
+ [InlineData("https://pic.twitter.com/gbxdb2Oj", false)]
+ [InlineData("https://twitter.com/messages/compose?recipient_id=514241801", true)]
+ [InlineData("http://twitter.com/messages/compose?recipient_id=514241801", true)]
+ [InlineData("https://twitter.com/messages/compose?recipient_id=514241801&text=%E3%81%BB%E3%81%92", true)]
+ public void AttachmentUrlRegexTest(string url, bool isMatch)
+ {
+ Assert.Equal(isMatch, Twitter.AttachmentUrlRegex.IsMatch(url));
+ }
+
+ [Theory]
[InlineData("http://favstar.fm/users/twitterapi/status/22634515958", new[] { "22634515958" })]
[InlineData("http://ja.favstar.fm/users/twitterapi/status/22634515958", new[] { "22634515958" })]
[InlineData("http://favstar.fm/t/22634515958", new[] { "22634515958" })]
{
var posts = new Dictionary<long, PostClass>
{
- {950L, new PostClass { StatusId = 950L, InReplyToStatusId = null }}, // このツイートが末端
- {987L, new PostClass { StatusId = 987L, InReplyToStatusId = 950L }},
- {999L, new PostClass { StatusId = 999L, InReplyToStatusId = 987L }},
- {1000L, new PostClass { StatusId = 1000L, InReplyToStatusId = 999L }},
+ [950L] = new PostClass { StatusId = 950L, InReplyToStatusId = null }, // このツイートが末端
+ [987L] = new PostClass { StatusId = 987L, InReplyToStatusId = 950L },
+ [999L] = new PostClass { StatusId = 999L, InReplyToStatusId = 987L },
+ [1000L] = new PostClass { StatusId = 1000L, InReplyToStatusId = 999L },
};
Assert.Equal(950L, Twitter.FindTopOfReplyChain(posts, 1000L).StatusId);
Assert.Equal(950L, Twitter.FindTopOfReplyChain(posts, 950L).StatusId);
posts = new Dictionary<long, PostClass>
{
// 1200L は posts の中に存在しない
- {1210L, new PostClass { StatusId = 1210L, InReplyToStatusId = 1200L }},
- {1220L, new PostClass { StatusId = 1220L, InReplyToStatusId = 1210L }},
- {1230L, new PostClass { StatusId = 1230L, InReplyToStatusId = 1220L }},
+ [1210L] = new PostClass { StatusId = 1210L, InReplyToStatusId = 1200L },
+ [1220L] = new PostClass { StatusId = 1220L, InReplyToStatusId = 1210L },
+ [1230L] = new PostClass { StatusId = 1230L, InReplyToStatusId = 1220L },
};
Assert.Equal(1210L, Twitter.FindTopOfReplyChain(posts, 1230L).StatusId);
Assert.Equal(1210L, Twitter.FindTopOfReplyChain(posts, 1210L).StatusId);
}
[Fact]
+ public void CreateAccessibleText_MediaAltTest()
+ {
+ var text = "https://t.co/hoge";
+ var entities = new TwitterEntities
+ {
+ Media = new[]
+ {
+ new TwitterEntityMedia
+ {
+ Indices = new[] { 0, 17 },
+ Url = "https://t.co/hoge",
+ DisplayUrl = "pic.twitter.com/hoge",
+ ExpandedUrl = "https://twitter.com/hoge/status/1234567890/photo/1",
+ AltText = "代替テキスト",
+ },
+ },
+ };
+
+ var expectedText = string.Format(Properties.Resources.ImageAltText, "代替テキスト");
+
+ Assert.Equal(expectedText, Twitter.CreateAccessibleText(text, entities, quotedStatus: null, quotedStatusLink: null));
+ }
+
+ [Fact]
+ public void CreateAccessibleText_MediaNoAltTest()
+ {
+ var text = "https://t.co/hoge";
+ var entities = new TwitterEntities
+ {
+ Media = new[]
+ {
+ new TwitterEntityMedia
+ {
+ Indices = new[] { 0, 17 },
+ Url = "https://t.co/hoge",
+ DisplayUrl = "pic.twitter.com/hoge",
+ ExpandedUrl = "https://twitter.com/hoge/status/1234567890/photo/1",
+ AltText = null,
+ },
+ },
+ };
+
+ var expectedText = "pic.twitter.com/hoge";
+
+ Assert.Equal(expectedText, Twitter.CreateAccessibleText(text, entities, quotedStatus: null, quotedStatusLink: null));
+ }
+
+ [Fact]
+ public void CreateAccessibleText_QuotedUrlTest()
+ {
+ var text = "https://t.co/hoge";
+ var entities = new TwitterEntities
+ {
+ Urls = new[]
+ {
+ new TwitterEntityUrl
+ {
+ Indices = new[] { 0, 17 },
+ Url = "https://t.co/hoge",
+ DisplayUrl = "twitter.com/hoge/status/1…",
+ ExpandedUrl = "https://twitter.com/hoge/status/1234567890",
+ },
+ },
+ };
+ var quotedStatus = new TwitterStatus
+ {
+ Id = 1234567890L,
+ IdStr = "1234567890",
+ User = new TwitterUser
+ {
+ Id = 1111,
+ IdStr = "1111",
+ ScreenName = "foo",
+ },
+ FullText = "test",
+ };
+
+ var expectedText = string.Format(Properties.Resources.QuoteStatus_AccessibleText, "foo", "test");
+
+ Assert.Equal(expectedText, Twitter.CreateAccessibleText(text, entities, quotedStatus, quotedStatusLink: null));
+ }
+
+ [Fact]
+ public void CreateAccessibleText_QuotedUrlWithPermelinkTest()
+ {
+ var text = "hoge";
+ var entities = new TwitterEntities();
+ var quotedStatus = new TwitterStatus
+ {
+ Id = 1234567890L,
+ IdStr = "1234567890",
+ User = new TwitterUser
+ {
+ Id = 1111,
+ IdStr = "1111",
+ ScreenName = "foo",
+ },
+ FullText = "test",
+ };
+ var quotedStatusLink = new TwitterQuotedStatusPermalink
+ {
+ Url = "https://t.co/hoge",
+ Display = "twitter.com/hoge/status/1…",
+ Expanded = "https://twitter.com/hoge/status/1234567890",
+ };
+
+ var expectedText = "hoge " + string.Format(Properties.Resources.QuoteStatus_AccessibleText, "foo", "test");
+
+ Assert.Equal(expectedText, Twitter.CreateAccessibleText(text, entities, quotedStatus, quotedStatusLink));
+ }
+
+ [Fact]
+ public void CreateAccessibleText_QuotedUrlNoReferenceTest()
+ {
+ var text = "https://t.co/hoge";
+ var entities = new TwitterEntities
+ {
+ Urls = new[]
+ {
+ new TwitterEntityUrl
+ {
+ Indices = new[] { 0, 17 },
+ Url = "https://t.co/hoge",
+ DisplayUrl = "twitter.com/hoge/status/1…",
+ ExpandedUrl = "https://twitter.com/hoge/status/1234567890",
+ },
+ },
+ };
+ var quotedStatus = (TwitterStatus)null;
+
+ var expectedText = "twitter.com/hoge/status/1…";
+
+ Assert.Equal(expectedText, Twitter.CreateAccessibleText(text, entities, quotedStatus, quotedStatusLink: null));
+ }
+
+ [Fact]
+ public void CreateHtmlAnchor_Test()
+ {
+ var text = "@twitterapi #BreakingMyTwitter https://t.co/mIJcSoVSK3";
+ var entities = new TwitterEntities
+ {
+ UserMentions = new[]
+ {
+ new TwitterEntityMention { Indices = new[] { 0, 11 }, ScreenName = "twitterapi" },
+ },
+ Hashtags = new[]
+ {
+ new TwitterEntityHashtag { Indices = new[] { 12, 30 }, Text = "BreakingMyTwitter" },
+ },
+ Urls = new[]
+ {
+ new TwitterEntityUrl
+ {
+ Indices = new[] { 31, 54 },
+ Url ="https://t.co/mIJcSoVSK3",
+ DisplayUrl = "apps-of-a-feather.com",
+ ExpandedUrl = "http://apps-of-a-feather.com/",
+ },
+ },
+ };
+
+ var expectedHtml = @"<a class=""mention"" href=""https://twitter.com/twitterapi"">@twitterapi</a>"
+ + @" <a class=""hashtag"" href=""https://twitter.com/search?q=%23BreakingMyTwitter"">#BreakingMyTwitter</a>"
+ + @" <a href=""https://t.co/mIJcSoVSK3"" title=""https://t.co/mIJcSoVSK3"">apps-of-a-feather.com</a>";
+
+ Assert.Equal(expectedHtml, Twitter.CreateHtmlAnchor(text, entities, quotedStatusLink: null));
+ }
+
+ [Fact]
+ public void CreateHtmlAnchor_NicovideoTest()
+ {
+ var text = "sm9";
+ var entities = new TwitterEntities();
+
+ var expectedHtml = @"<a href=""http://www.nicovideo.jp/watch/sm9"">sm9</a>";
+
+ Assert.Equal(expectedHtml, Twitter.CreateHtmlAnchor(text, entities, quotedStatusLink: null));
+ }
+
+ [Fact]
+ public void CreateHtmlAnchor_QuotedUrlWithPermelinkTest()
+ {
+ var text = "hoge";
+ var entities = new TwitterEntities();
+ var quotedStatus = new TwitterStatus
+ {
+ Id = 1234567890L,
+ IdStr = "1234567890",
+ User = new TwitterUser
+ {
+ Id = 1111,
+ IdStr = "1111",
+ ScreenName = "foo",
+ },
+ FullText = "test",
+ };
+ var quotedStatusLink = new TwitterQuotedStatusPermalink
+ {
+ Url = "https://t.co/hoge",
+ Display = "twitter.com/hoge/status/1…",
+ Expanded = "https://twitter.com/hoge/status/1234567890",
+ };
+
+ var expectedHtml = @"hoge"
+ + @" <a href=""https://t.co/hoge"" title=""https://t.co/hoge"">twitter.com/hoge/status/1…</a>";
+
+ Assert.Equal(expectedHtml, Twitter.CreateHtmlAnchor(text, entities, quotedStatusLink));
+ }
+
+ [Fact]
public void ParseSource_Test()
{
var sourceHtml = "<a href=\"http://twitter.com\" rel=\"nofollow\">Twitter Web Client</a>";
- var result = Twitter.ParseSource(sourceHtml);
- Assert.Equal("Twitter Web Client", result.Item1);
- Assert.Equal(new Uri("http://twitter.com/"), result.Item2);
+ var expected = ("Twitter Web Client", new Uri("http://twitter.com/"));
+ Assert.Equal(expected, Twitter.ParseSource(sourceHtml));
}
[Fact]
{
var sourceHtml = "web";
- var result = Twitter.ParseSource(sourceHtml);
- Assert.Equal("web", result.Item1);
- Assert.Equal(null, result.Item2);
+ var expected = ("web", (Uri)null);
+ Assert.Equal(expected, Twitter.ParseSource(sourceHtml));
}
[Fact]
// 参照: https://twitter.com/kim_upsilon/status/477796052049752064
var sourceHtml = "<a href=\"erased_45416\" rel=\"nofollow\">erased_45416</a>";
- var result = Twitter.ParseSource(sourceHtml);
- Assert.Equal("erased_45416", result.Item1);
- Assert.Equal(new Uri("https://twitter.com/erased_45416"), result.Item2);
+ var expected = ("erased_45416", new Uri("https://twitter.com/erased_45416"));
+ Assert.Equal(expected, Twitter.ParseSource(sourceHtml));
}
[Fact]
// 参照: https://twitter.com/kim_upsilon/status/595156014032244738
var sourceHtml = "";
- var result = Twitter.ParseSource(sourceHtml);
- Assert.Equal("", result.Item1);
- Assert.Equal(null, result.Item2);
+ var expected = ("", (Uri)null);
+ Assert.Equal(expected, Twitter.ParseSource(sourceHtml));
}
[Fact]
{
string sourceHtml = null;
- var result = Twitter.ParseSource(sourceHtml);
- Assert.Equal("", result.Item1);
- Assert.Equal(null, result.Item2);
+ var expected = ("", (Uri)null);
+ Assert.Equal(expected, Twitter.ParseSource(sourceHtml));
}
[Fact]
{
string sourceHtml = "<a href=\"http://example.com/?aaa=123&bbb=456\" rel=\"nofollow\"><<hogehoge>></a>";
- var result = Twitter.ParseSource(sourceHtml);
- Assert.Equal("<<hogehoge>>", result.Item1);
- Assert.Equal(new Uri("http://example.com/?aaa=123&bbb=456"), result.Item2);
+ var expected = ("<<hogehoge>>", new Uri("http://example.com/?aaa=123&bbb=456"));
+ Assert.Equal(expected, Twitter.ParseSource(sourceHtml));
}
[Fact]
{
string sourceHtml = "<<hogehoge>>";
- var result = Twitter.ParseSource(sourceHtml);
- Assert.Equal("<<hogehoge>>", result.Item1);
- Assert.Equal(null, result.Item2);
+ var expected = ("<<hogehoge>>", (Uri)null);
+ Assert.Equal(expected, Twitter.ParseSource(sourceHtml));
}
[Fact]
- public void GetQuoteTweetStatusIds_Test()
+ public void GetQuoteTweetStatusIds_EntityTest()
{
var entities = new[]
{
},
};
- var statusIds = Twitter.GetQuoteTweetStatusIds(entities);
+ var statusIds = Twitter.GetQuoteTweetStatusIds(entities, quotedStatusLink: null);
Assert.Equal(new[] { 599261132361072640L }, statusIds);
}
[Fact]
+ public void GetQuoteTweetStatusIds_QuotedStatusLinkTest()
+ {
+ var entities = new TwitterEntities();
+ var quotedStatusLink = new TwitterQuotedStatusPermalink
+ {
+ Url = "https://t.co/3HXq0LrbJb",
+ Expanded = "https://twitter.com/kim_upsilon/status/599261132361072640",
+ };
+
+ var statusIds = Twitter.GetQuoteTweetStatusIds(entities, quotedStatusLink);
+ Assert.Equal(new[] { 599261132361072640L }, statusIds);
+ }
+
+ [Fact]
+ public void GetQuoteTweetStatusIds_UrlStringTest()
+ {
+ var urls = new[]
+ {
+ "https://twitter.com/kim_upsilon/status/599261132361072640",
+ };
+
+ var statusIds = Twitter.GetQuoteTweetStatusIds(urls);
+ Assert.Equal(new[] { 599261132361072640L }, statusIds);
+ }
+
+ [Fact]
+ public void GetQuoteTweetStatusIds_OverflowTest()
+ {
+ var urls = new[]
+ {
+ // 符号付き 64 ビット整数の範囲を超える値
+ "https://twitter.com/kim_upsilon/status/9999999999999999999",
+ };
+
+ var statusIds = Twitter.GetQuoteTweetStatusIds(urls);
+ Assert.Empty(statusIds);
+ }
+
+ [Fact]
public void GetApiResultCount_DefaultTest()
{
- var oldInstance = SettingCommon.Instance;
- SettingCommon.Instance = new SettingCommon();
+ var oldInstance = SettingManagerTest.Common;
+ SettingManagerTest.Common = new SettingCommon();
- var timeline = SettingCommon.Instance.CountApi;
- var reply = SettingCommon.Instance.CountApiReply;
+ var timeline = SettingManager.Common.CountApi;
+ var reply = SettingManager.Common.CountApiReply;
var dm = 20; // DMは固定値
- var more = SettingCommon.Instance.MoreCountApi;
- var startup = SettingCommon.Instance.FirstCountApi;
- var favorite = SettingCommon.Instance.FavoritesCountApi;
- var list = SettingCommon.Instance.ListCountApi;
- var search = SettingCommon.Instance.SearchCountApi;
- var usertl = SettingCommon.Instance.UserTimelineCountApi;
+ var more = SettingManager.Common.MoreCountApi;
+ var startup = SettingManager.Common.FirstCountApi;
+ var favorite = SettingManager.Common.FavoritesCountApi;
+ var list = SettingManager.Common.ListCountApi;
+ var search = SettingManager.Common.SearchCountApi;
+ var usertl = SettingManager.Common.UserTimelineCountApi;
// デフォルト値チェック
- Assert.Equal(false, SettingCommon.Instance.UseAdditionalCount);
+ Assert.False(SettingManager.Common.UseAdditionalCount);
Assert.Equal(60, timeline);
Assert.Equal(40, reply);
Assert.Equal(200, more);
Assert.Equal(timeline, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.PublicSearch, false, false));
Assert.Equal(timeline, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.UserTimeline, false, false));
- SettingCommon.Instance = oldInstance;
+ SettingManagerTest.Common = oldInstance;
}
[Fact]
public void GetApiResultCount_AdditionalCountTest()
{
- var oldInstance = SettingCommon.Instance;
- SettingCommon.Instance = new SettingCommon();
+ var oldInstance = SettingManagerTest.Common;
+ SettingManagerTest.Common = new SettingCommon();
- var timeline = SettingCommon.Instance.CountApi;
- var reply = SettingCommon.Instance.CountApiReply;
+ var timeline = SettingManager.Common.CountApi;
+ var reply = SettingManager.Common.CountApiReply;
var dm = 20; // DMは固定値
- var more = SettingCommon.Instance.MoreCountApi;
- var startup = SettingCommon.Instance.FirstCountApi;
- var favorite = SettingCommon.Instance.FavoritesCountApi;
- var list = SettingCommon.Instance.ListCountApi;
- var search = SettingCommon.Instance.SearchCountApi;
- var usertl = SettingCommon.Instance.UserTimelineCountApi;
+ var more = SettingManager.Common.MoreCountApi;
+ var startup = SettingManager.Common.FirstCountApi;
+ var favorite = SettingManager.Common.FavoritesCountApi;
+ var list = SettingManager.Common.ListCountApi;
+ var search = SettingManager.Common.SearchCountApi;
+ var usertl = SettingManager.Common.UserTimelineCountApi;
- SettingCommon.Instance.UseAdditionalCount = true;
+ SettingManager.Common.UseAdditionalCount = true;
// Timeline
Assert.Equal(timeline, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.Timeline, false, false));
Assert.Equal(favorite, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.Favorites, true, false));
Assert.Equal(favorite, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.Favorites, false, true));
- SettingCommon.Instance.FavoritesCountApi = 0;
+ SettingManager.Common.FavoritesCountApi = 0;
Assert.Equal(timeline, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.Favorites, false, false));
Assert.Equal(more, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.Favorites, true, false));
Assert.Equal(list, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.List, true, false));
Assert.Equal(list, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.List, false, true));
- SettingCommon.Instance.ListCountApi = 0;
+ SettingManager.Common.ListCountApi = 0;
Assert.Equal(timeline, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.List, false, false));
Assert.Equal(more, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.List, true, false));
Assert.Equal(search, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.PublicSearch, true, false));
Assert.Equal(search, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.PublicSearch, false, true));
- SettingCommon.Instance.SearchCountApi = 0;
+ SettingManager.Common.SearchCountApi = 0;
Assert.Equal(timeline, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.PublicSearch, false, false));
Assert.Equal(search, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.PublicSearch, true, false)); //MoreCountApiの値がPublicSearchの最大値に制限される
Assert.Equal(usertl, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.UserTimeline, true, false));
Assert.Equal(usertl, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.UserTimeline, false, true));
- SettingCommon.Instance.UserTimelineCountApi = 0;
+ SettingManager.Common.UserTimelineCountApi = 0;
Assert.Equal(timeline, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.UserTimeline, false, false));
Assert.Equal(more, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.UserTimeline, true, false));
Assert.Equal(startup, Twitter.GetApiResultCount(MyCommon.WORKERTYPE.UserTimeline, false, true));
- SettingCommon.Instance = oldInstance;
+ SettingManagerTest.Common = oldInstance;
+ }
+
+ [Fact]
+ public void GetTextLengthRemain_Test()
+ {
+ using (var twitter = new Twitter())
+ {
+ Assert.Equal(280, twitter.GetTextLengthRemain(""));
+ Assert.Equal(272, twitter.GetTextLengthRemain("hogehoge"));
+ }
+ }
+
+ [Fact]
+ public void GetTextLengthRemain_DirectMessageTest()
+ {
+ using (var twitter = new Twitter())
+ {
+ // 2015年8月から DM の文字数上限が 10,000 文字に変更された
+ // https://twittercommunity.com/t/41348
+ twitter.Configuration.DmTextCharacterLimit = 10000;
+
+ Assert.Equal(10000, twitter.GetTextLengthRemain("D twitter "));
+ Assert.Equal(9992, twitter.GetTextLengthRemain("D twitter hogehoge"));
+
+ // t.co に短縮される分の文字数を考慮
+ twitter.Configuration.ShortUrlLength = 20;
+ Assert.Equal(9971, twitter.GetTextLengthRemain("D twitter hogehoge http://example.com/"));
+
+ twitter.Configuration.ShortUrlLengthHttps = 21;
+ Assert.Equal(9970, twitter.GetTextLengthRemain("D twitter hogehoge https://example.com/"));
+ }
+ }
+
+ [Fact]
+ public void GetTextLengthRemain_UrlTest()
+ {
+ using (var twitter = new Twitter())
+ {
+ // t.co に短縮される分の文字数を考慮
+ twitter.TextConfiguration.TransformedURLLength = 20;
+ Assert.Equal(260, twitter.GetTextLengthRemain("http://example.com/"));
+ Assert.Equal(260, twitter.GetTextLengthRemain("http://example.com/hogehoge"));
+ Assert.Equal(251, twitter.GetTextLengthRemain("hogehoge http://example.com/"));
+
+ Assert.Equal(260, twitter.GetTextLengthRemain("https://example.com/"));
+ Assert.Equal(260, twitter.GetTextLengthRemain("https://example.com/hogehoge"));
+ Assert.Equal(251, twitter.GetTextLengthRemain("hogehoge https://example.com/"));
+ }
+ }
+
+ [Fact]
+ public void GetTextLengthRemain_UrlWithoutSchemeTest()
+ {
+ using (var twitter = new Twitter())
+ {
+ // t.co に短縮される分の文字数を考慮
+ twitter.TextConfiguration.TransformedURLLength = 20;
+ Assert.Equal(260, twitter.GetTextLengthRemain("example.com"));
+ Assert.Equal(260, twitter.GetTextLengthRemain("example.com/hogehoge"));
+ Assert.Equal(251, twitter.GetTextLengthRemain("hogehoge example.com"));
+
+ // スキーム (http://) を省略かつ末尾が ccTLD の場合は t.co に短縮されない
+ Assert.Equal(270, twitter.GetTextLengthRemain("example.jp"));
+ // ただし、末尾にパスが続く場合は t.co に短縮される
+ Assert.Equal(260, twitter.GetTextLengthRemain("example.jp/hogehoge"));
+ }
+ }
+
+ [Fact]
+ public void GetTextLengthRemain_SurrogatePairTest()
+ {
+ using (var twitter = new Twitter())
+ {
+ Assert.Equal(278, twitter.GetTextLengthRemain("🍣"));
+ Assert.Equal(267, twitter.GetTextLengthRemain("🔥🐔🔥 焼き鳥"));
+ }
+ }
+
+ [Fact]
+ public void GetTextLengthRemain_BrokenSurrogateTest()
+ {
+ using (var twitter = new Twitter())
+ {
+ // 投稿欄に IME から絵文字を入力すると HighSurrogate のみ入力された状態で TextChanged イベントが呼ばれることがある
+ Assert.Equal(278, twitter.GetTextLengthRemain("\ud83d"));
+ Assert.Equal(9999, twitter.GetTextLengthRemain("D twitter \ud83d"));
+ }
}
}
}