OSDN Git Service

Twitter.PostStatusメソッドにattachmentUrl引数を追加
[opentween/open-tween.git] / OpenTween.Tests / Api / TwitterApiTest.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2016 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
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)
10 // any later version.
11 //
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
15 // for more details.
16 //
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.
21
22 using System;
23 using System.Collections.Generic;
24 using System.IO;
25 using System.Linq;
26 using System.Net.Http;
27 using System.Reflection;
28 using System.Runtime.InteropServices;
29 using System.Text;
30 using System.Threading.Tasks;
31 using Moq;
32 using OpenTween.Api.DataModel;
33 using OpenTween.Connection;
34 using Xunit;
35
36 namespace OpenTween.Api
37 {
38     public class TwitterApiTest
39     {
40         public TwitterApiTest()
41         {
42             this.MyCommonSetup();
43         }
44
45         public void MyCommonSetup()
46         {
47             var mockAssembly = new Mock<_Assembly>();
48             mockAssembly.Setup(m => m.GetName()).Returns(new AssemblyName("OpenTween"));
49
50             MyCommon.EntryAssembly = mockAssembly.Object;
51         }
52
53         [Fact]
54         public void Initialize_Test()
55         {
56             using (var twitterApi = new TwitterApi())
57             {
58                 Assert.Null(twitterApi.apiConnection);
59
60                 twitterApi.Initialize("*** AccessToken ***", "*** AccessSecret ***", userId: 100L, screenName: "hogehoge");
61
62                 Assert.IsType<TwitterApiConnection>(twitterApi.apiConnection);
63
64                 var apiConnection = (TwitterApiConnection)twitterApi.apiConnection;
65                 Assert.Equal("*** AccessToken ***", apiConnection.AccessToken);
66                 Assert.Equal("*** AccessSecret ***", apiConnection.AccessSecret);
67
68                 Assert.Equal(100L, twitterApi.CurrentUserId);
69                 Assert.Equal("hogehoge", twitterApi.CurrentScreenName);
70
71                 // 複数回 Initialize を実行した場合は新たに TwitterApiConnection が生成される
72                 twitterApi.Initialize("*** AccessToken2 ***", "*** AccessSecret2 ***", userId: 200L, screenName: "foobar");
73
74                 var oldApiConnection = apiConnection;
75                 Assert.True(oldApiConnection.IsDisposed);
76
77                 Assert.IsType<TwitterApiConnection>(twitterApi.apiConnection);
78
79                 apiConnection = (TwitterApiConnection)twitterApi.apiConnection;
80                 Assert.Equal("*** AccessToken2 ***", apiConnection.AccessToken);
81                 Assert.Equal("*** AccessSecret2 ***", apiConnection.AccessSecret);
82
83                 Assert.Equal(200L, twitterApi.CurrentUserId);
84                 Assert.Equal("foobar", twitterApi.CurrentScreenName);
85             }
86         }
87
88         [Fact]
89         public async Task StatusesHomeTimeline_Test()
90         {
91             using (var twitterApi = new TwitterApi())
92             {
93                 var mock = new Mock<IApiConnection>();
94                 mock.Setup(x =>
95                     x.GetAsync<TwitterStatus[]>(
96                         new Uri("statuses/home_timeline.json", UriKind.Relative),
97                         new Dictionary<string, string> {
98                             { "include_entities", "true" },
99                             { "include_ext_alt_text", "true" },
100                             { "tweet_mode", "extended" },
101                             { "count", "200" },
102                             { "max_id", "900" },
103                             { "since_id", "100" },
104                         },
105                         "/statuses/home_timeline")
106                 )
107                 .ReturnsAsync(new TwitterStatus[0]);
108
109                 twitterApi.apiConnection = mock.Object;
110
111                 await twitterApi.StatusesHomeTimeline(200, maxId: 900L, sinceId: 100L)
112                     .ConfigureAwait(false);
113
114                 mock.VerifyAll();
115             }
116         }
117
118         [Fact]
119         public async Task StatusesMentionsTimeline_Test()
120         {
121             using (var twitterApi = new TwitterApi())
122             {
123                 var mock = new Mock<IApiConnection>();
124                 mock.Setup(x =>
125                     x.GetAsync<TwitterStatus[]>(
126                         new Uri("statuses/mentions_timeline.json", UriKind.Relative),
127                         new Dictionary<string, string> {
128                             { "include_entities", "true" },
129                             { "include_ext_alt_text", "true" },
130                             { "tweet_mode", "extended" },
131                             { "count", "200" },
132                             { "max_id", "900" },
133                             { "since_id", "100" },
134                         },
135                         "/statuses/mentions_timeline")
136                 )
137                 .ReturnsAsync(new TwitterStatus[0]);
138
139                 twitterApi.apiConnection = mock.Object;
140
141                 await twitterApi.StatusesMentionsTimeline(200, maxId: 900L, sinceId: 100L)
142                     .ConfigureAwait(false);
143
144                 mock.VerifyAll();
145             }
146         }
147
148         [Fact]
149         public async Task StatusesUserTimeline_Test()
150         {
151             using (var twitterApi = new TwitterApi())
152             {
153                 var mock = new Mock<IApiConnection>();
154                 mock.Setup(x =>
155                     x.GetAsync<TwitterStatus[]>(
156                         new Uri("statuses/user_timeline.json", UriKind.Relative),
157                         new Dictionary<string, string> {
158                             { "screen_name", "twitterapi" },
159                             { "include_rts", "true" },
160                             { "include_entities", "true" },
161                             { "include_ext_alt_text", "true" },
162                             { "tweet_mode", "extended" },
163                             { "count", "200" },
164                             { "max_id", "900" },
165                             { "since_id", "100" },
166                         },
167                         "/statuses/user_timeline")
168                 )
169                 .ReturnsAsync(new TwitterStatus[0]);
170
171                 twitterApi.apiConnection = mock.Object;
172
173                 await twitterApi.StatusesUserTimeline("twitterapi", count: 200, maxId: 900L, sinceId: 100L)
174                     .ConfigureAwait(false);
175
176                 mock.VerifyAll();
177             }
178         }
179
180         [Fact]
181         public async Task StatusesShow_Test()
182         {
183             using (var twitterApi = new TwitterApi())
184             {
185                 var mock = new Mock<IApiConnection>();
186                 mock.Setup(x =>
187                     x.GetAsync<TwitterStatus>(
188                         new Uri("statuses/show.json", UriKind.Relative),
189                         new Dictionary<string, string> {
190                             { "id", "100" },
191                             { "include_entities", "true" },
192                             { "include_ext_alt_text", "true" },
193                             { "tweet_mode", "extended" },
194                         },
195                         "/statuses/show/:id")
196                 )
197                 .ReturnsAsync(new TwitterStatus { Id = 100L });
198
199                 twitterApi.apiConnection = mock.Object;
200
201                 await twitterApi.StatusesShow(statusId: 100L)
202                     .ConfigureAwait(false);
203
204                 mock.VerifyAll();
205             }
206         }
207
208         [Fact]
209         public async Task StatusesUpdate_Test()
210         {
211             using (var twitterApi = new TwitterApi())
212             {
213                 var mock = new Mock<IApiConnection>();
214                 mock.Setup(x =>
215                     x.PostLazyAsync<TwitterStatus>(
216                         new Uri("statuses/update.json", UriKind.Relative),
217                         new Dictionary<string, string> {
218                             { "status", "hogehoge" },
219                             { "include_entities", "true" },
220                             { "include_ext_alt_text", "true" },
221                             { "tweet_mode", "extended" },
222                             { "in_reply_to_status_id", "100" },
223                             { "media_ids", "10,20" },
224                             { "auto_populate_reply_metadata", "true" },
225                             { "exclude_reply_user_ids", "100,200" },
226                             { "attachment_url", "https://twitter.com/twitterapi/status/22634515958" },
227                         })
228                 )
229                 .ReturnsAsync(LazyJson.Create(new TwitterStatus()));
230
231                 twitterApi.apiConnection = mock.Object;
232
233                 await twitterApi.StatusesUpdate("hogehoge", replyToId: 100L, mediaIds: new[] { 10L, 20L },
234                         autoPopulateReplyMetadata: true, excludeReplyUserIds: new[] { 100L, 200L },
235                         attachmentUrl: "https://twitter.com/twitterapi/status/22634515958")
236                     .IgnoreResponse()
237                     .ConfigureAwait(false);
238
239                 mock.VerifyAll();
240             }
241         }
242
243         [Fact]
244         public async Task StatusesUpdate_ExcludeReplyUserIdsEmptyTest()
245         {
246             using (var twitterApi = new TwitterApi())
247             {
248                 var mock = new Mock<IApiConnection>();
249                 mock.Setup(x =>
250                     x.PostLazyAsync<TwitterStatus>(
251                         new Uri("statuses/update.json", UriKind.Relative),
252                         new Dictionary<string, string> {
253                             { "status", "hogehoge" },
254                             { "include_entities", "true" },
255                             { "include_ext_alt_text", "true" },
256                             { "tweet_mode", "extended" },
257                             // exclude_reply_user_ids は空の場合には送信されない
258                         })
259                 )
260                 .ReturnsAsync(LazyJson.Create(new TwitterStatus()));
261
262                 twitterApi.apiConnection = mock.Object;
263
264                 await twitterApi.StatusesUpdate("hogehoge", replyToId: null, mediaIds: null, excludeReplyUserIds: new long[0])
265                     .IgnoreResponse()
266                     .ConfigureAwait(false);
267
268                 mock.VerifyAll();
269             }
270         }
271
272         [Fact]
273         public async Task StatusesDestroy_Test()
274         {
275             using (var twitterApi = new TwitterApi())
276             {
277                 var mock = new Mock<IApiConnection>();
278                 mock.Setup(x =>
279                     x.PostLazyAsync<TwitterStatus>(
280                         new Uri("statuses/destroy.json", UriKind.Relative),
281                         new Dictionary<string, string> { { "id", "100" } })
282                 )
283                 .ReturnsAsync(LazyJson.Create(new TwitterStatus { Id = 100L }));
284
285                 twitterApi.apiConnection = mock.Object;
286
287                 await twitterApi.StatusesDestroy(statusId: 100L)
288                     .IgnoreResponse()
289                     .ConfigureAwait(false);
290
291                 mock.VerifyAll();
292             }
293         }
294
295         [Fact]
296         public async Task StatusesRetweet_Test()
297         {
298             using (var twitterApi = new TwitterApi())
299             {
300                 var mock = new Mock<IApiConnection>();
301                 mock.Setup(x =>
302                     x.PostLazyAsync<TwitterStatus>(
303                         new Uri("statuses/retweet.json", UriKind.Relative),
304                         new Dictionary<string, string> {
305                             { "id", "100" },
306                             { "include_entities", "true" },
307                             { "include_ext_alt_text", "true" },
308                             { "tweet_mode", "extended" },
309                         })
310                 )
311                 .ReturnsAsync(LazyJson.Create(new TwitterStatus()));
312
313                 twitterApi.apiConnection = mock.Object;
314
315                 await twitterApi.StatusesRetweet(100L)
316                     .IgnoreResponse()
317                     .ConfigureAwait(false);
318
319                 mock.VerifyAll();
320             }
321         }
322
323         [Fact]
324         public async Task SearchTweets_Test()
325         {
326             using (var twitterApi = new TwitterApi())
327             {
328                 var mock = new Mock<IApiConnection>();
329                 mock.Setup(x =>
330                     x.GetAsync<TwitterSearchResult>(
331                         new Uri("search/tweets.json", UriKind.Relative),
332                         new Dictionary<string, string> {
333                             { "q", "from:twitterapi" },
334                             { "result_type", "recent" },
335                             { "include_entities", "true" },
336                             { "include_ext_alt_text", "true" },
337                             { "tweet_mode", "extended" },
338                             { "lang", "en" },
339                             { "count", "200" },
340                             { "max_id", "900" },
341                             { "since_id", "100" },
342                         },
343                         "/search/tweets")
344                 )
345                 .ReturnsAsync(new TwitterSearchResult());
346
347                 twitterApi.apiConnection = mock.Object;
348
349                 await twitterApi.SearchTweets("from:twitterapi", "en", count: 200, maxId: 900L, sinceId: 100L)
350                     .ConfigureAwait(false);
351
352                 mock.VerifyAll();
353             }
354         }
355
356         [Fact]
357         public async Task ListsOwnerships_Test()
358         {
359             using (var twitterApi = new TwitterApi())
360             {
361                 var mock = new Mock<IApiConnection>();
362                 mock.Setup(x =>
363                     x.GetAsync<TwitterLists>(
364                         new Uri("lists/ownerships.json", UriKind.Relative),
365                         new Dictionary<string, string> {
366                             { "screen_name", "twitterapi" },
367                             { "cursor", "-1" },
368                             { "count", "100" },
369                         },
370                         "/lists/ownerships")
371                 )
372                 .ReturnsAsync(new TwitterLists());
373
374                 twitterApi.apiConnection = mock.Object;
375
376                 await twitterApi.ListsOwnerships("twitterapi", cursor: -1L, count: 100)
377                     .ConfigureAwait(false);
378
379                 mock.VerifyAll();
380             }
381         }
382
383         [Fact]
384         public async Task ListsSubscriptions_Test()
385         {
386             using (var twitterApi = new TwitterApi())
387             {
388                 var mock = new Mock<IApiConnection>();
389                 mock.Setup(x =>
390                     x.GetAsync<TwitterLists>(
391                         new Uri("lists/subscriptions.json", UriKind.Relative),
392                         new Dictionary<string, string> {
393                             { "screen_name", "twitterapi" },
394                             { "cursor", "-1" },
395                             { "count", "100" },
396                         },
397                         "/lists/subscriptions")
398                 )
399                 .ReturnsAsync(new TwitterLists());
400
401                 twitterApi.apiConnection = mock.Object;
402
403                 await twitterApi.ListsSubscriptions("twitterapi", cursor: -1L, count: 100)
404                     .ConfigureAwait(false);
405
406                 mock.VerifyAll();
407             }
408         }
409
410         [Fact]
411         public async Task ListsMemberships_Test()
412         {
413             using (var twitterApi = new TwitterApi())
414             {
415                 var mock = new Mock<IApiConnection>();
416                 mock.Setup(x =>
417                     x.GetAsync<TwitterLists>(
418                         new Uri("lists/memberships.json", UriKind.Relative),
419                         new Dictionary<string, string> {
420                             { "screen_name", "twitterapi" },
421                             { "cursor", "-1" },
422                             { "count", "100" },
423                             { "filter_to_owned_lists", "true" },
424                         },
425                         "/lists/memberships")
426                 )
427                 .ReturnsAsync(new TwitterLists());
428
429                 twitterApi.apiConnection = mock.Object;
430
431                 await twitterApi.ListsMemberships("twitterapi", cursor: -1L, count: 100, filterToOwnedLists: true)
432                     .ConfigureAwait(false);
433
434                 mock.VerifyAll();
435             }
436         }
437
438         [Fact]
439         public async Task ListsCreate_Test()
440         {
441             using (var twitterApi = new TwitterApi())
442             {
443                 var mock = new Mock<IApiConnection>();
444                 mock.Setup(x =>
445                     x.PostLazyAsync<TwitterList>(
446                         new Uri("lists/create.json", UriKind.Relative),
447                         new Dictionary<string, string> {
448                             { "name", "hogehoge" },
449                             { "description", "aaaa" },
450                             { "mode", "private" },
451                         })
452                 )
453                 .ReturnsAsync(LazyJson.Create(new TwitterList()));
454
455                 twitterApi.apiConnection = mock.Object;
456
457                 await twitterApi.ListsCreate("hogehoge", description: "aaaa", @private: true)
458                     .IgnoreResponse()
459                     .ConfigureAwait(false);
460
461                 mock.VerifyAll();
462             }
463         }
464
465         [Fact]
466         public async Task ListsUpdate_Test()
467         {
468             using (var twitterApi = new TwitterApi())
469             {
470                 var mock = new Mock<IApiConnection>();
471                 mock.Setup(x =>
472                     x.PostLazyAsync<TwitterList>(
473                         new Uri("lists/update.json", UriKind.Relative),
474                         new Dictionary<string, string> {
475                             { "list_id", "12345" },
476                             { "name", "hogehoge" },
477                             { "description", "aaaa" },
478                             { "mode", "private" },
479                         })
480                 )
481                 .ReturnsAsync(LazyJson.Create(new TwitterList()));
482
483                 twitterApi.apiConnection = mock.Object;
484
485                 await twitterApi.ListsUpdate(12345L, name: "hogehoge", description: "aaaa", @private: true)
486                     .IgnoreResponse()
487                     .ConfigureAwait(false);
488
489                 mock.VerifyAll();
490             }
491         }
492
493         [Fact]
494         public async Task ListsDestroy_Test()
495         {
496             using (var twitterApi = new TwitterApi())
497             {
498                 var mock = new Mock<IApiConnection>();
499                 mock.Setup(x =>
500                     x.PostLazyAsync<TwitterList>(
501                         new Uri("lists/destroy.json", UriKind.Relative),
502                         new Dictionary<string, string> {
503                             { "list_id", "12345" },
504                         })
505                 )
506                 .ReturnsAsync(LazyJson.Create(new TwitterList()));
507
508                 twitterApi.apiConnection = mock.Object;
509
510                 await twitterApi.ListsDestroy(12345L)
511                     .IgnoreResponse()
512                     .ConfigureAwait(false);
513
514                 mock.VerifyAll();
515             }
516         }
517
518         [Fact]
519         public async Task ListsStatuses_Test()
520         {
521             using (var twitterApi = new TwitterApi())
522             {
523                 var mock = new Mock<IApiConnection>();
524                 mock.Setup(x =>
525                     x.GetAsync<TwitterStatus[]>(
526                         new Uri("lists/statuses.json", UriKind.Relative),
527                         new Dictionary<string, string> {
528                             { "list_id", "12345" },
529                             { "include_entities", "true" },
530                             { "include_ext_alt_text", "true" },
531                             { "tweet_mode", "extended" },
532                             { "count", "200" },
533                             { "max_id", "900" },
534                             { "since_id", "100" },
535                             { "include_rts", "true" },
536                         },
537                         "/lists/statuses")
538                 )
539                 .ReturnsAsync(new TwitterStatus[0]);
540
541                 twitterApi.apiConnection = mock.Object;
542
543                 await twitterApi.ListsStatuses(12345L, count: 200, maxId: 900L, sinceId: 100L, includeRTs: true)
544                     .ConfigureAwait(false);
545
546                 mock.VerifyAll();
547             }
548         }
549
550         [Fact]
551         public async Task ListsMembers_Test()
552         {
553             using (var twitterApi = new TwitterApi())
554             {
555                 var mock = new Mock<IApiConnection>();
556                 mock.Setup(x =>
557                     x.GetAsync<TwitterUsers>(
558                         new Uri("lists/members.json", UriKind.Relative),
559                         new Dictionary<string, string> {
560                             { "list_id", "12345" },
561                             { "include_entities", "true" },
562                             { "include_ext_alt_text", "true" },
563                             { "tweet_mode", "extended" },
564                             { "cursor", "-1" },
565                         },
566                         "/lists/members")
567                 )
568                 .ReturnsAsync(new TwitterUsers());
569
570                 twitterApi.apiConnection = mock.Object;
571
572                 await twitterApi.ListsMembers(12345L, cursor: -1)
573                     .ConfigureAwait(false);
574
575                 mock.VerifyAll();
576             }
577         }
578
579         [Fact]
580         public async Task ListsMembersShow_Test()
581         {
582             using (var twitterApi = new TwitterApi())
583             {
584                 var mock = new Mock<IApiConnection>();
585                 mock.Setup(x =>
586                     x.GetAsync<TwitterUser>(
587                         new Uri("lists/members/show.json", UriKind.Relative),
588                         new Dictionary<string, string> {
589                             { "list_id", "12345" },
590                             { "screen_name", "twitterapi" },
591                             { "include_entities", "true" },
592                             { "include_ext_alt_text", "true" },
593                             { "tweet_mode", "extended" },
594                         },
595                         "/lists/members/show")
596                 )
597                 .ReturnsAsync(new TwitterUser());
598
599                 twitterApi.apiConnection = mock.Object;
600
601                 await twitterApi.ListsMembersShow(12345L, "twitterapi")
602                     .ConfigureAwait(false);
603
604                 mock.VerifyAll();
605             }
606         }
607
608         [Fact]
609         public async Task ListsMembersCreate_Test()
610         {
611             using (var twitterApi = new TwitterApi())
612             {
613                 var mock = new Mock<IApiConnection>();
614                 mock.Setup(x =>
615                     x.PostLazyAsync<TwitterUser>(
616                         new Uri("lists/members/create.json", UriKind.Relative),
617                         new Dictionary<string, string> {
618                             { "list_id", "12345" },
619                             { "screen_name", "twitterapi" },
620                             { "include_entities", "true" },
621                             { "include_ext_alt_text", "true" },
622                             { "tweet_mode", "extended" },
623                         })
624                 )
625                 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
626
627                 twitterApi.apiConnection = mock.Object;
628
629                 await twitterApi.ListsMembersCreate(12345L, "twitterapi")
630                     .IgnoreResponse()
631                     .ConfigureAwait(false);
632
633                 mock.VerifyAll();
634             }
635         }
636
637         [Fact]
638         public async Task ListsMembersDestroy_Test()
639         {
640             using (var twitterApi = new TwitterApi())
641             {
642                 var mock = new Mock<IApiConnection>();
643                 mock.Setup(x =>
644                     x.PostLazyAsync<TwitterUser>(
645                         new Uri("lists/members/destroy.json", UriKind.Relative),
646                         new Dictionary<string, string> {
647                             { "list_id", "12345" },
648                             { "screen_name", "twitterapi" },
649                             { "include_entities", "true" },
650                             { "include_ext_alt_text", "true" },
651                             { "tweet_mode", "extended" },
652                         })
653                 )
654                 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
655
656                 twitterApi.apiConnection = mock.Object;
657
658                 await twitterApi.ListsMembersDestroy(12345L, "twitterapi")
659                     .IgnoreResponse()
660                     .ConfigureAwait(false);
661
662                 mock.VerifyAll();
663             }
664         }
665
666         [Fact]
667         public async Task DirectMessagesRecv_Test()
668         {
669             using (var twitterApi = new TwitterApi())
670             {
671                 var mock = new Mock<IApiConnection>();
672                 mock.Setup(x =>
673                     x.GetAsync<TwitterDirectMessage[]>(
674                         new Uri("direct_messages.json", UriKind.Relative),
675                         new Dictionary<string, string> {
676                             { "full_text", "true" },
677                             { "include_entities", "true" },
678                             { "include_ext_alt_text", "true" },
679                             { "count", "200" },
680                             { "max_id", "900" },
681                             { "since_id", "100" },
682                         },
683                         "/direct_messages")
684                 )
685                 .ReturnsAsync(new TwitterDirectMessage[0]);
686
687                 twitterApi.apiConnection = mock.Object;
688
689                 await twitterApi.DirectMessagesRecv(count: 200, maxId: 900L, sinceId: 100L)
690                     .ConfigureAwait(false);
691
692                 mock.VerifyAll();
693             }
694         }
695
696         [Fact]
697         public async Task DirectMessagesSent_Test()
698         {
699             using (var twitterApi = new TwitterApi())
700             {
701                 var mock = new Mock<IApiConnection>();
702                 mock.Setup(x =>
703                     x.GetAsync<TwitterDirectMessage[]>(
704                         new Uri("direct_messages/sent.json", UriKind.Relative),
705                         new Dictionary<string, string> {
706                             { "full_text", "true" },
707                             { "include_entities", "true" },
708                             { "include_ext_alt_text", "true" },
709                             { "count", "200" },
710                             { "max_id", "900" },
711                             { "since_id", "100" },
712                         },
713                         "/direct_messages/sent")
714                 )
715                 .ReturnsAsync(new TwitterDirectMessage[0]);
716
717                 twitterApi.apiConnection = mock.Object;
718
719                 await twitterApi.DirectMessagesSent(count: 200, maxId: 900L, sinceId: 100L)
720                     .ConfigureAwait(false);
721
722                 mock.VerifyAll();
723             }
724         }
725
726         [Fact]
727         public async Task DirectMessagesNew_Test()
728         {
729             using (var twitterApi = new TwitterApi())
730             {
731                 var mock = new Mock<IApiConnection>();
732                 mock.Setup(x =>
733                     x.PostLazyAsync<TwitterDirectMessage>(
734                         new Uri("direct_messages/new.json", UriKind.Relative),
735                         new Dictionary<string, string> {
736                             { "text", "hogehoge" },
737                             { "screen_name", "opentween" },
738                         })
739                 )
740                 .ReturnsAsync(LazyJson.Create(new TwitterDirectMessage()));
741
742                 twitterApi.apiConnection = mock.Object;
743
744                 await twitterApi.DirectMessagesNew("hogehoge", "opentween")
745                     .IgnoreResponse()
746                     .ConfigureAwait(false);
747
748                 mock.VerifyAll();
749             }
750         }
751
752         [Fact]
753         public async Task DirectMessagesDestroy_Test()
754         {
755             using (var twitterApi = new TwitterApi())
756             {
757                 var mock = new Mock<IApiConnection>();
758                 mock.Setup(x =>
759                     x.PostLazyAsync<TwitterDirectMessage>(
760                         new Uri("direct_messages/destroy.json", UriKind.Relative),
761                         new Dictionary<string, string> { { "id", "100" } })
762                 )
763                 .ReturnsAsync(LazyJson.Create(new TwitterDirectMessage { Id = 100L }));
764
765                 twitterApi.apiConnection = mock.Object;
766
767                 await twitterApi.DirectMessagesDestroy(statusId: 100L)
768                     .IgnoreResponse()
769                     .ConfigureAwait(false);
770
771                 mock.VerifyAll();
772             }
773         }
774
775         [Fact]
776         public async Task UsersShow_Test()
777         {
778             using (var twitterApi = new TwitterApi())
779             {
780                 var mock = new Mock<IApiConnection>();
781                 mock.Setup(x =>
782                     x.GetAsync<TwitterUser>(
783                         new Uri("users/show.json", UriKind.Relative),
784                         new Dictionary<string, string> {
785                             { "screen_name", "twitterapi" },
786                             { "include_entities", "true" },
787                             { "include_ext_alt_text", "true" },
788                             { "tweet_mode", "extended" },
789                         },
790                         "/users/show/:id")
791                 )
792                 .ReturnsAsync(new TwitterUser { ScreenName = "twitterapi" });
793
794                 twitterApi.apiConnection = mock.Object;
795
796                 await twitterApi.UsersShow(screenName: "twitterapi")
797                     .ConfigureAwait(false);
798
799                 mock.VerifyAll();
800             }
801         }
802
803         [Fact]
804         public async Task UsersReportSpam_Test()
805         {
806             using (var twitterApi = new TwitterApi())
807             {
808                 var mock = new Mock<IApiConnection>();
809                 mock.Setup(x =>
810                     x.PostLazyAsync<TwitterUser>(
811                         new Uri("users/report_spam.json", UriKind.Relative),
812                         new Dictionary<string, string> {
813                             { "screen_name", "twitterapi" },
814                             { "tweet_mode", "extended" },
815                         })
816                 )
817                 .ReturnsAsync(LazyJson.Create(new TwitterUser { ScreenName = "twitterapi" }));
818
819                 twitterApi.apiConnection = mock.Object;
820
821                 await twitterApi.UsersReportSpam(screenName: "twitterapi")
822                     .IgnoreResponse()
823                     .ConfigureAwait(false);
824
825                 mock.VerifyAll();
826             }
827         }
828
829         [Fact]
830         public async Task FavoritesList_Test()
831         {
832             using (var twitterApi = new TwitterApi())
833             {
834                 var mock = new Mock<IApiConnection>();
835                 mock.Setup(x =>
836                     x.GetAsync<TwitterStatus[]>(
837                         new Uri("favorites/list.json", UriKind.Relative),
838                         new Dictionary<string, string> {
839                             { "include_entities", "true" },
840                             { "include_ext_alt_text", "true" },
841                             { "tweet_mode", "extended" },
842                             { "count", "200" },
843                             { "max_id", "900" },
844                             { "since_id", "100" },
845                         },
846                         "/favorites/list")
847                 )
848                 .ReturnsAsync(new TwitterStatus[0]);
849
850                 twitterApi.apiConnection = mock.Object;
851
852                 await twitterApi.FavoritesList(200, maxId: 900L, sinceId: 100L)
853                     .ConfigureAwait(false);
854
855                 mock.VerifyAll();
856             }
857         }
858
859         [Fact]
860         public async Task FavoritesCreate_Test()
861         {
862             using (var twitterApi = new TwitterApi())
863             {
864                 var mock = new Mock<IApiConnection>();
865                 mock.Setup(x =>
866                     x.PostLazyAsync<TwitterStatus>(
867                         new Uri("favorites/create.json", UriKind.Relative),
868                         new Dictionary<string, string> {
869                             { "id", "100" },
870                             { "tweet_mode", "extended" },
871                         })
872                 )
873                 .ReturnsAsync(LazyJson.Create(new TwitterStatus { Id = 100L }));
874
875                 twitterApi.apiConnection = mock.Object;
876
877                 await twitterApi.FavoritesCreate(statusId: 100L)
878                     .IgnoreResponse()
879                     .ConfigureAwait(false);
880
881                 mock.VerifyAll();
882             }
883         }
884
885         [Fact]
886         public async Task FavoritesDestroy_Test()
887         {
888             using (var twitterApi = new TwitterApi())
889             {
890                 var mock = new Mock<IApiConnection>();
891                 mock.Setup(x =>
892                     x.PostLazyAsync<TwitterStatus>(
893                         new Uri("favorites/destroy.json", UriKind.Relative),
894                         new Dictionary<string, string> {
895                             { "id", "100" },
896                             { "tweet_mode", "extended" },
897                         })
898                 )
899                 .ReturnsAsync(LazyJson.Create(new TwitterStatus { Id = 100L }));
900
901                 twitterApi.apiConnection = mock.Object;
902
903                 await twitterApi.FavoritesDestroy(statusId: 100L)
904                     .IgnoreResponse()
905                     .ConfigureAwait(false);
906
907                 mock.VerifyAll();
908             }
909         }
910
911         [Fact]
912         public async Task FriendshipsShow_Test()
913         {
914             using (var twitterApi = new TwitterApi())
915             {
916                 var mock = new Mock<IApiConnection>();
917                 mock.Setup(x =>
918                     x.GetAsync<TwitterFriendship>(
919                         new Uri("friendships/show.json", UriKind.Relative),
920                         new Dictionary<string, string> { { "source_screen_name", "twitter" }, { "target_screen_name", "twitterapi" } },
921                         "/friendships/show")
922                 )
923                 .ReturnsAsync(new TwitterFriendship());
924
925                 twitterApi.apiConnection = mock.Object;
926
927                 await twitterApi.FriendshipsShow(sourceScreenName: "twitter", targetScreenName: "twitterapi")
928                     .ConfigureAwait(false);
929
930                 mock.VerifyAll();
931             }
932         }
933
934         [Fact]
935         public async Task FriendshipsCreate_Test()
936         {
937             using (var twitterApi = new TwitterApi())
938             {
939                 var mock = new Mock<IApiConnection>();
940                 mock.Setup(x =>
941                     x.PostLazyAsync<TwitterFriendship>(
942                         new Uri("friendships/create.json", UriKind.Relative),
943                         new Dictionary<string, string> { { "screen_name", "twitterapi" } })
944                 )
945                 .ReturnsAsync(LazyJson.Create(new TwitterFriendship()));
946
947                 twitterApi.apiConnection = mock.Object;
948
949                 await twitterApi.FriendshipsCreate(screenName: "twitterapi")
950                     .IgnoreResponse()
951                     .ConfigureAwait(false);
952
953                 mock.VerifyAll();
954             }
955         }
956
957         [Fact]
958         public async Task FriendshipsDestroy_Test()
959         {
960             using (var twitterApi = new TwitterApi())
961             {
962                 var mock = new Mock<IApiConnection>();
963                 mock.Setup(x =>
964                     x.PostLazyAsync<TwitterFriendship>(
965                         new Uri("friendships/destroy.json", UriKind.Relative),
966                         new Dictionary<string, string> { { "screen_name", "twitterapi" } })
967                 )
968                 .ReturnsAsync(LazyJson.Create(new TwitterFriendship()));
969
970                 twitterApi.apiConnection = mock.Object;
971
972                 await twitterApi.FriendshipsDestroy(screenName: "twitterapi")
973                     .IgnoreResponse()
974                     .ConfigureAwait(false);
975
976                 mock.VerifyAll();
977             }
978         }
979
980         [Fact]
981         public async Task NoRetweetIds_Test()
982         {
983             using (var twitterApi = new TwitterApi())
984             {
985                 var mock = new Mock<IApiConnection>();
986                 mock.Setup(x =>
987                     x.GetAsync<long[]>(
988                         new Uri("friendships/no_retweets/ids.json", UriKind.Relative),
989                         null,
990                         "/friendships/no_retweets/ids")
991                 )
992                 .ReturnsAsync(new long[0]);
993
994                 twitterApi.apiConnection = mock.Object;
995
996                 await twitterApi.NoRetweetIds()
997                     .ConfigureAwait(false);
998
999                 mock.VerifyAll();
1000             }
1001         }
1002
1003         [Fact]
1004         public async Task FollowersIds_Test()
1005         {
1006             using (var twitterApi = new TwitterApi())
1007             {
1008                 var mock = new Mock<IApiConnection>();
1009                 mock.Setup(x =>
1010                     x.GetAsync<TwitterIds>(
1011                         new Uri("followers/ids.json", UriKind.Relative),
1012                         new Dictionary<string, string> { { "cursor", "-1" } },
1013                         "/followers/ids")
1014                 )
1015                 .ReturnsAsync(new TwitterIds());
1016
1017                 twitterApi.apiConnection = mock.Object;
1018
1019                 await twitterApi.FollowersIds(cursor: -1L)
1020                     .ConfigureAwait(false);
1021
1022                 mock.VerifyAll();
1023             }
1024         }
1025
1026         [Fact]
1027         public async Task MutesUsersIds_Test()
1028         {
1029             using (var twitterApi = new TwitterApi())
1030             {
1031                 var mock = new Mock<IApiConnection>();
1032                 mock.Setup(x =>
1033                     x.GetAsync<TwitterIds>(
1034                         new Uri("mutes/users/ids.json", UriKind.Relative),
1035                         new Dictionary<string, string> { { "cursor", "-1" } },
1036                         "/mutes/users/ids")
1037                 )
1038                 .ReturnsAsync(new TwitterIds());
1039
1040                 twitterApi.apiConnection = mock.Object;
1041
1042                 await twitterApi.MutesUsersIds(cursor: -1L)
1043                     .ConfigureAwait(false);
1044
1045                 mock.VerifyAll();
1046             }
1047         }
1048
1049         [Fact]
1050         public async Task BlocksIds_Test()
1051         {
1052             using (var twitterApi = new TwitterApi())
1053             {
1054                 var mock = new Mock<IApiConnection>();
1055                 mock.Setup(x =>
1056                     x.GetAsync<TwitterIds>(
1057                         new Uri("blocks/ids.json", UriKind.Relative),
1058                         new Dictionary<string, string> { { "cursor", "-1" } },
1059                         "/blocks/ids")
1060                 )
1061                 .ReturnsAsync(new TwitterIds());
1062
1063                 twitterApi.apiConnection = mock.Object;
1064
1065                 await twitterApi.BlocksIds(cursor: -1L)
1066                     .ConfigureAwait(false);
1067
1068                 mock.VerifyAll();
1069             }
1070         }
1071
1072         [Fact]
1073         public async Task BlocksCreate_Test()
1074         {
1075             using (var twitterApi = new TwitterApi())
1076             {
1077                 var mock = new Mock<IApiConnection>();
1078                 mock.Setup(x =>
1079                     x.PostLazyAsync<TwitterUser>(
1080                         new Uri("blocks/create.json", UriKind.Relative),
1081                         new Dictionary<string, string> {
1082                             { "screen_name", "twitterapi" },
1083                             { "tweet_mode", "extended" },
1084                         })
1085                 )
1086                 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
1087
1088                 twitterApi.apiConnection = mock.Object;
1089
1090                 await twitterApi.BlocksCreate(screenName: "twitterapi")
1091                     .IgnoreResponse()
1092                     .ConfigureAwait(false);
1093
1094                 mock.VerifyAll();
1095             }
1096         }
1097
1098         [Fact]
1099         public async Task BlocksDestroy_Test()
1100         {
1101             using (var twitterApi = new TwitterApi())
1102             {
1103                 var mock = new Mock<IApiConnection>();
1104                 mock.Setup(x =>
1105                     x.PostLazyAsync<TwitterUser>(
1106                         new Uri("blocks/destroy.json", UriKind.Relative),
1107                         new Dictionary<string, string> {
1108                             { "screen_name", "twitterapi" },
1109                             { "tweet_mode", "extended" },
1110                         })
1111                 )
1112                 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
1113
1114                 twitterApi.apiConnection = mock.Object;
1115
1116                 await twitterApi.BlocksDestroy(screenName: "twitterapi")
1117                     .IgnoreResponse()
1118                     .ConfigureAwait(false);
1119
1120                 mock.VerifyAll();
1121             }
1122         }
1123
1124         [Fact]
1125         public async Task AccountVerifyCredentials_Test()
1126         {
1127             using (var twitterApi = new TwitterApi())
1128             {
1129                 var mock = new Mock<IApiConnection>();
1130                 mock.Setup(x =>
1131                     x.GetAsync<TwitterUser>(
1132                         new Uri("account/verify_credentials.json", UriKind.Relative),
1133                         new Dictionary<string, string> {
1134                             { "include_entities", "true" },
1135                             { "include_ext_alt_text", "true" },
1136                             { "tweet_mode", "extended" },
1137                         },
1138                         "/account/verify_credentials")
1139                 )
1140                 .ReturnsAsync(new TwitterUser {
1141                     Id = 100L,
1142                     ScreenName = "opentween",
1143                 });
1144
1145                 twitterApi.apiConnection = mock.Object;
1146
1147                 await twitterApi.AccountVerifyCredentials()
1148                     .ConfigureAwait(false);
1149
1150                 Assert.Equal(100L, twitterApi.CurrentUserId);
1151                 Assert.Equal("opentween", twitterApi.CurrentScreenName);
1152
1153                 mock.VerifyAll();
1154             }
1155         }
1156
1157         [Fact]
1158         public async Task AccountUpdateProfile_Test()
1159         {
1160             using (var twitterApi = new TwitterApi())
1161             {
1162                 var mock = new Mock<IApiConnection>();
1163                 mock.Setup(x =>
1164                     x.PostLazyAsync<TwitterUser>(
1165                         new Uri("account/update_profile.json", UriKind.Relative),
1166                         new Dictionary<string, string> {
1167                             { "include_entities", "true" },
1168                             { "include_ext_alt_text", "true" },
1169                             { "tweet_mode", "extended" },
1170                             { "name", "Name" },
1171                             { "url", "http://example.com/" },
1172                             { "location", "Location" },
1173                             { "description", "&lt;script&gt;alert(1)&lt;/script&gt;" },
1174                         })
1175                 )
1176                 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
1177
1178                 twitterApi.apiConnection = mock.Object;
1179
1180                 await twitterApi.AccountUpdateProfile(name: "Name", url: "http://example.com/", location: "Location", description: "<script>alert(1)</script>")
1181                     .IgnoreResponse()
1182                     .ConfigureAwait(false);
1183
1184                 mock.VerifyAll();
1185             }
1186         }
1187
1188         [Fact]
1189         public async Task AccountUpdateProfileImage_Test()
1190         {
1191             using (var twitterApi = new TwitterApi())
1192             using (var image = TestUtils.CreateDummyImage())
1193             using (var media = new MemoryImageMediaItem(image))
1194             {
1195                 var mock = new Mock<IApiConnection>();
1196                 mock.Setup(x =>
1197                     x.PostLazyAsync<TwitterUser>(
1198                         new Uri("account/update_profile_image.json", UriKind.Relative),
1199                         new Dictionary<string, string> {
1200                             { "include_entities", "true" },
1201                             { "include_ext_alt_text", "true" },
1202                             { "tweet_mode", "extended" },
1203                         },
1204                         new Dictionary<string, IMediaItem> { { "image", media } })
1205                 )
1206                 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
1207
1208                 twitterApi.apiConnection = mock.Object;
1209
1210                 await twitterApi.AccountUpdateProfileImage(media)
1211                     .IgnoreResponse()
1212                     .ConfigureAwait(false);
1213
1214                 mock.VerifyAll();
1215             }
1216         }
1217
1218         [Fact]
1219         public async Task ApplicationRateLimitStatus_Test()
1220         {
1221             using (var twitterApi = new TwitterApi())
1222             {
1223                 var mock = new Mock<IApiConnection>();
1224                 mock.Setup(x =>
1225                     x.GetAsync<TwitterRateLimits>(
1226                         new Uri("application/rate_limit_status.json", UriKind.Relative),
1227                         null,
1228                         "/application/rate_limit_status")
1229                 )
1230                 .ReturnsAsync(new TwitterRateLimits());
1231
1232                 twitterApi.apiConnection = mock.Object;
1233
1234                 await twitterApi.ApplicationRateLimitStatus()
1235                     .ConfigureAwait(false);
1236
1237                 mock.VerifyAll();
1238             }
1239         }
1240
1241         [Fact]
1242         public async Task Configuration_Test()
1243         {
1244             using (var twitterApi = new TwitterApi())
1245             {
1246                 var mock = new Mock<IApiConnection>();
1247                 mock.Setup(x =>
1248                     x.GetAsync<TwitterConfiguration>(
1249                         new Uri("help/configuration.json", UriKind.Relative),
1250                         null,
1251                         "/help/configuration")
1252                 )
1253                 .ReturnsAsync(new TwitterConfiguration());
1254
1255                 twitterApi.apiConnection = mock.Object;
1256
1257                 await twitterApi.Configuration()
1258                     .ConfigureAwait(false);
1259
1260                 mock.VerifyAll();
1261             }
1262         }
1263
1264         [Fact]
1265         public async Task MediaUpload_Test()
1266         {
1267             using (var twitterApi = new TwitterApi())
1268             using (var image = TestUtils.CreateDummyImage())
1269             using (var media = new MemoryImageMediaItem(image))
1270             {
1271                 var mock = new Mock<IApiConnection>();
1272                 mock.Setup(x =>
1273                     x.PostLazyAsync<TwitterUploadMediaResult>(
1274                         new Uri("https://upload.twitter.com/1.1/media/upload.json", UriKind.Absolute),
1275                         null,
1276                         new Dictionary<string, IMediaItem> { { "media", media } })
1277                 )
1278                 .ReturnsAsync(LazyJson.Create(new TwitterUploadMediaResult()));
1279
1280                 twitterApi.apiConnection = mock.Object;
1281
1282                 await twitterApi.MediaUpload(media)
1283                     .IgnoreResponse()
1284                     .ConfigureAwait(false);
1285
1286                 mock.VerifyAll();
1287             }
1288         }
1289
1290         [Fact]
1291         public async Task MediaMetadataCreate_Test()
1292         {
1293             using (var twitterApi = new TwitterApi())
1294             {
1295                 var mock = new Mock<IApiConnection>();
1296                 mock.Setup(x =>
1297                     x.PostJsonAsync(
1298                         new Uri("https://upload.twitter.com/1.1/media/metadata/create.json", UriKind.Absolute),
1299                         "{\"media_id\": \"12345\", \"alt_text\": {\"text\": \"hogehoge\"}}")
1300                 )
1301                 .Returns(Task.FromResult(0));
1302
1303                 twitterApi.apiConnection = mock.Object;
1304
1305                 await twitterApi.MediaMetadataCreate(mediaId: 12345L, altText: "hogehoge")
1306                     .ConfigureAwait(false);
1307
1308                 mock.VerifyAll();
1309             }
1310         }
1311
1312         [Fact]
1313         public async Task UserStreams_Test()
1314         {
1315             using (var twitterApi = new TwitterApi())
1316             {
1317                 var mock = new Mock<IApiConnection>();
1318                 mock.Setup(x =>
1319                     x.GetStreamingStreamAsync(
1320                         new Uri("https://userstream.twitter.com/1.1/user.json", UriKind.Absolute),
1321                         new Dictionary<string, string> {
1322                             { "replies", "all" },
1323                             { "track", "OpenTween" },
1324                         })
1325                 )
1326                 .ReturnsAsync(new MemoryStream());
1327
1328                 twitterApi.apiConnection = mock.Object;
1329
1330                 var stream = await twitterApi.UserStreams(replies: "all", track: "OpenTween")
1331                     .ConfigureAwait(false);
1332
1333                 stream.Dispose();
1334
1335                 mock.VerifyAll();
1336             }
1337         }
1338
1339         [Theory]
1340         [InlineData("", "")]
1341         [InlineData("123ABCabc", "123ABCabc")]
1342         [InlineData(@"\", @"\\")]
1343         [InlineData("\"", "\\\"")]
1344         [InlineData("\n", @"\u000A")]
1345         [InlineData("\U0001D11E", @"\uD834\uDD1E")]
1346         public void EscapeJsonString_Test(string targetText, string expectedText)
1347         {
1348             Assert.Equal(expectedText, TwitterApi.EscapeJsonString(targetText));
1349         }
1350     }
1351 }