OSDN Git Service

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