OSDN Git Service

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