1 // OpenTween - Client of Twitter
2 // Copyright (c) 2014 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
23 using System.Collections.Generic;
28 using Xunit.Extensions;
32 public class TweetFormatterTest
35 public void FormatUrlEntity_Test()
37 var text = "http://t.co/KYi7vMZzRt";
42 Indices = new[] { 0, 22 },
43 DisplayUrl = "twitter.com",
44 ExpandedUrl = "http://twitter.com/",
45 Url = "http://t.co/KYi7vMZzRt",
49 var expected = "<a href=\"http://t.co/KYi7vMZzRt\" title=\"http://twitter.com/\">twitter.com</a>";
50 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
54 public void FormatHashtagEntity_Test()
56 var text = "#OpenTween";
59 new TwitterEntityHashtag
61 Indices = new[] { 0, 10 },
66 var expected = "<a class=\"hashtag\" href=\"https://twitter.com/search?q=%23OpenTween\">#OpenTween</a>";
67 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
71 public void FormatMentionEntity_Test()
73 var text = "@TwitterAPI";
76 new TwitterEntityMention
78 Indices = new[] { 0, 11 },
81 ScreenName = "twitterapi",
85 var expected = "<a class=\"mention\" href=\"https://twitter.com/twitterapi\">@TwitterAPI</a>";
86 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
90 public void FormatMediaEntity_Test()
92 var text = "http://t.co/h5dCr4ftN4";
95 new TwitterEntityMedia
97 Indices = new[] { 0, 22 },
98 Sizes = new TwitterMediaSizes
100 Large = new TwitterMediaSizes.Size { Resize = "fit", Height = 329, Width = 1024 },
101 Medium = new TwitterMediaSizes.Size { Resize = "fit", Height = 204, Width = 600 },
102 Small = new TwitterMediaSizes.Size { Resize = "fit", Height = 116, Width = 340 },
103 Thumb = new TwitterMediaSizes.Size { Resize = "crop", Height = 150, Width = 150 },
106 Id = 426404550379986940L,
107 MediaUrl = "http://pbs.twimg.com/media/BerkrewCYAAV4Kf.png",
108 MediaUrlHttps = "https://pbs.twimg.com/media/BerkrewCYAAV4Kf.png",
109 Url = "http://t.co/h5dCr4ftN4",
110 DisplayUrl = "pic.twitter.com/h5dCr4ftN4",
111 ExpandedUrl = "http://twitter.com/kim_upsilon/status/426404550371598337/photo/1",
115 var expected = "<a href=\"http://t.co/h5dCr4ftN4\" title=\"http://twitter.com/kim_upsilon/status/426404550371598337/photo/1\">pic.twitter.com/h5dCr4ftN4</a>";
116 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
120 public void AutoLinkHtml_EntityNullTest()
122 var text = "てすとてすとー";
123 TwitterEntities entities = null;
125 var expected = "てすとてすとー";
126 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
130 public void AutoLinkHtml_EntityNullTest2()
132 var text = "てすとてすとー";
133 TwitterEntities entities = new TwitterEntities
141 var expected = "てすとてすとー";
142 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
146 public void AutoLinkHtml_EntityNullTest3()
148 var text = "てすとてすとー";
149 IEnumerable<TwitterEntity> entities = null;
151 var expected = "てすとてすとー";
152 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
156 public void AutoLinkHtml_EntityNullTest4()
158 var text = "てすとてすとー";
159 IEnumerable<TwitterEntity> entities = new TwitterEntity[] { null };
161 var expected = "てすとてすとー";
162 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
166 public void AutoLinkHtml_EscapeTest()
168 // Twitter APIの中途半端なエスケープの対象とならない「"」や「'」に対するエスケープ処理を施す
169 var text = "\"\'@twitterapi\'\"";
172 new TwitterEntityMention
174 Indices = new[] { 2, 13 },
176 Name = "Twitter API",
177 ScreenName = "twitterapi",
181 var expected = ""'<a class=\"mention\" href=\"https://twitter.com/twitterapi\">@twitterapi</a>'"";
182 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
186 public void AutoLinkHtml_EscapeTest2()
188 // 「<」や「>」についてはエスケープされた状態でAPIからテキストが返されるため、二重エスケープとならないように考慮する
189 var text = "<b> @twitterapi </b>";
192 new TwitterEntityMention
194 Indices = new[] { 10, 21 },
196 Name = "Twitter API",
197 ScreenName = "twitterapi",
201 var expected = "<b> <a class=\"mention\" href=\"https://twitter.com/twitterapi\">@twitterapi</a> </b>";
202 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
206 public void AutoLinkHtml_EscapeTest3()
208 // 万が一「<」や「>」がエスケープされていない状態のテキストを受け取っても適切にエスケープが施されるようにする
209 var text = "<b> @twitterapi </b>";
212 new TwitterEntityMention
214 Indices = new[] { 4, 15 },
216 Name = "Twitter API",
217 ScreenName = "twitterapi",
221 var expected = "<b> <a class=\"mention\" href=\"https://twitter.com/twitterapi\">@twitterapi</a> </b>";
222 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
226 public void AutoLinkHtml_EscapeUrlTest()
228 // 日本語ハッシュタグのリンク先URLを適切にエスケープする
229 var text = "#ぜんぶ雪のせいだ";
232 new TwitterEntityHashtag
234 Indices = new[] { 0, 9 },
239 var expected = "<a class=\"hashtag\" href=\"https://twitter.com/search?q=%23%E3%81%9C%E3%82%93%E3%81%B6%E9%9B%AA%E3%81%AE%E3%81%9B%E3%81%84%E3%81%A0\">#ぜんぶ雪のせいだ</a>";
240 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
244 public void AutoLinkHtml_SurrogatePairTest()
246 // UTF-16 で 4 バイトで表される文字を含むツイート
247 // 参照: https://sourceforge.jp/ticket/browse.php?group_id=6526&tid=33079
248 var text = "🐬🐬 @irucame 🐬🐬";
251 new TwitterEntityMention
253 Indices = new[] { 3, 11 },
255 ScreenName = "irucame",
259 var expected = "🐬🐬 <a class=\"mention\" href=\"https://twitter.com/irucame\">@irucame</a> 🐬🐬";
260 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
264 public void AutoLinkHtml_SurrogatePairTest2()
266 // 現時点では存在しないものの、ハッシュタグなどエンティティ内にサロゲートペアが含まれる場合も考慮する
267 var text = "🐬🐬 #🐬🐬 🐬🐬 #🐬🐬 🐬🐬";
270 new TwitterEntityHashtag
272 Indices = new[] { 3, 6 },
275 new TwitterEntityHashtag
277 Indices = new[] { 10, 13 },
282 var expected = "🐬🐬 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23%F0%9F%90%AC%F0%9F%90%AC\">#🐬🐬</a> " +
283 "🐬🐬 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23%F0%9F%90%AC%F0%9F%90%AC\">#🐬🐬</a> 🐬🐬";
284 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
288 public void AutoLinkHtml_CompositeCharacterTest()
290 // 合成文字 é ( \u00e9 ) を含むツイート
291 // 参照: https://dev.twitter.com/issues/251
292 var text = "Caf\u00e9 #test";
295 new TwitterEntityHashtag
297 Indices = new[] { 5, 10 },
302 var expected = "Caf\u00e9 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23test\">#test</a>";
303 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
307 public void AutoLinkHtml_CombiningCharacterSequenceTest()
309 // 結合文字列 é ( e + \u0301 ) を含むツイート
310 // 参照: https://dev.twitter.com/issues/251
311 var text = "Cafe\u0301 #test";
314 new TwitterEntityHashtag
316 Indices = new[] { 6, 11 },
321 var expected = "Cafe\u0301 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23test\">#test</a>";
322 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
326 public void AutoLinkHtml_BreakLineTest()
328 var text = "てすと\nてすと\nてすと";
329 TwitterEntities entities = null;
331 var expected = "てすと<br>てすと<br>てすと";
332 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
336 public void AutoLinkHtml_OverlappedEntitiesTest()
338 // extended_entities で追加される、区間が重複したエンティティを考慮
339 // 参照: https://dev.twitter.com/docs/api/multiple-media-extended-entities
341 var text = "\"I hope you'll keep...building bonds of friendship that will enrich your lives & enrich our world\" \u2014FLOTUS in China, http://t.co/fxmuQN9JL9";
344 new TwitterEntityMedia
346 DisplayUrl = "pic.twitter.com/fxmuQN9JL9",
347 ExpandedUrl = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
348 Indices = new[] { 121, 143 },
349 MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EH6yIQAEYvxu.jpg",
350 Url = "http://t.co/fxmuQN9JL9",
352 new TwitterEntityMedia
354 DisplayUrl = "pic.twitter.com/fxmuQN9JL9",
355 ExpandedUrl = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
356 Indices = new[] { 121, 143 },
357 MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EHxAIIAE8dtg.jpg",
358 Url = "http://t.co/fxmuQN9JL9",
360 new TwitterEntityMedia
362 DisplayUrl = "pic.twitter.com/fxmuQN9JL9",
363 ExpandedUrl = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
364 Indices = new[] { 121, 143 },
365 MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EH3pIYAE4LQn.jpg",
366 Url = "http://t.co/fxmuQN9JL9",
368 new TwitterEntityMedia
370 DisplayUrl = "pic.twitter.com/fxmuQN9JL9",
371 ExpandedUrl = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
372 Indices = new[] { 121, 143 },
373 MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EL3DIEAAzGAX.jpg",
374 Url = "http://t.co/fxmuQN9JL9",
378 var expected = ""I hope you'll keep...building bonds of friendship that will enrich your lives & enrich our world" \u2014FLOTUS in China, " +
379 "<a href=\"http://t.co/fxmuQN9JL9\" title=\"http://twitter.com/FLOTUS/status/449660889793581056/photo/1\">pic.twitter.com/fxmuQN9JL9</a>";
380 Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));