1 // OpenTween - Client of Twitter
2 // Copyright (c) 2016 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
23 using System.Collections.Generic;
27 using System.Net.Http;
28 using System.Reflection;
29 using System.Runtime.InteropServices;
31 using System.Threading.Tasks;
33 using OpenTween.Api.DataModel;
34 using OpenTween.Connection;
37 namespace OpenTween.Api
39 public class TwitterApiTest
41 public TwitterApiTest()
42 => this.MyCommonSetup();
44 private void MyCommonSetup()
46 var mockAssembly = new Mock<_Assembly>();
47 mockAssembly.Setup(m => m.GetName()).Returns(new AssemblyName("OpenTween"));
49 MyCommon.EntryAssembly = mockAssembly.Object;
53 public void Initialize_Test()
55 using var twitterApi = new TwitterApi();
56 var apiConnection = Assert.IsType<TwitterApiConnection>(twitterApi.Connection);
57 Assert.IsType<TwitterCredentialNone>(apiConnection.Credential);
59 var credential = new TwitterCredentialOAuth1(TwitterAppToken.GetDefault(), "*** AccessToken ***", "*** AccessSecret ***");
60 twitterApi.Initialize(credential, userId: 100L, screenName: "hogehoge");
62 apiConnection = Assert.IsType<TwitterApiConnection>(twitterApi.Connection);
63 Assert.Same(credential, apiConnection.Credential);
65 Assert.Equal(100L, twitterApi.CurrentUserId);
66 Assert.Equal("hogehoge", twitterApi.CurrentScreenName);
68 // 複数回 Initialize を実行した場合は新たに TwitterApiConnection が生成される
69 var credential2 = new TwitterCredentialOAuth1(TwitterAppToken.GetDefault(), "*** AccessToken2 ***", "*** AccessSecret2 ***");
70 twitterApi.Initialize(credential2, userId: 200L, screenName: "foobar");
72 var oldApiConnection = apiConnection;
73 Assert.True(oldApiConnection.IsDisposed);
75 apiConnection = Assert.IsType<TwitterApiConnection>(twitterApi.Connection);
76 Assert.Same(credential2, apiConnection.Credential);
78 Assert.Equal(200L, twitterApi.CurrentUserId);
79 Assert.Equal("foobar", twitterApi.CurrentScreenName);
82 private Mock<IApiConnectionLegacy> CreateApiConnectionMock<T>(Action<T> verifyRequest)
83 where T : IHttpRequest
85 Func<T, bool> verifyRequestWrapper = r =>
88 // Assert メソッドを使用する想定のため、失敗した場合は例外が発生しここまで到達しない
92 var responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
93 var mock = new Mock<IApiConnectionLegacy>();
96 It.Is<T>(r => verifyRequestWrapper(r))
99 .ReturnsAsync(new ApiResponse(responseMessage));
105 public async Task StatusesHomeTimeline_Test()
107 var mock = new Mock<IApiConnectionLegacy>();
109 x.GetAsync<TwitterStatus[]>(
110 new Uri("statuses/home_timeline.json", UriKind.Relative),
111 new Dictionary<string, string>
113 { "include_entities", "true" },
114 { "include_ext_alt_text", "true" },
115 { "tweet_mode", "extended" },
118 { "since_id", "100" },
120 "/statuses/home_timeline")
122 .ReturnsAsync(Array.Empty<TwitterStatus>());
124 using var twitterApi = new TwitterApi();
125 twitterApi.ApiConnection = mock.Object;
127 await twitterApi.StatusesHomeTimeline(200, maxId: new("900"), sinceId: new("100"));
133 public async Task StatusesMentionsTimeline_Test()
135 var mock = new Mock<IApiConnectionLegacy>();
137 x.GetAsync<TwitterStatus[]>(
138 new Uri("statuses/mentions_timeline.json", UriKind.Relative),
139 new Dictionary<string, string>
141 { "include_entities", "true" },
142 { "include_ext_alt_text", "true" },
143 { "tweet_mode", "extended" },
146 { "since_id", "100" },
148 "/statuses/mentions_timeline")
150 .ReturnsAsync(Array.Empty<TwitterStatus>());
152 using var twitterApi = new TwitterApi();
153 twitterApi.ApiConnection = mock.Object;
155 await twitterApi.StatusesMentionsTimeline(200, maxId: new("900"), sinceId: new("100"));
161 public async Task StatusesUserTimeline_Test()
163 var mock = new Mock<IApiConnectionLegacy>();
165 x.GetAsync<TwitterStatus[]>(
166 new Uri("statuses/user_timeline.json", UriKind.Relative),
167 new Dictionary<string, string>
169 { "screen_name", "twitterapi" },
170 { "include_rts", "true" },
171 { "include_entities", "true" },
172 { "include_ext_alt_text", "true" },
173 { "tweet_mode", "extended" },
176 { "since_id", "100" },
178 "/statuses/user_timeline")
180 .ReturnsAsync(Array.Empty<TwitterStatus>());
182 using var twitterApi = new TwitterApi();
183 twitterApi.ApiConnection = mock.Object;
185 await twitterApi.StatusesUserTimeline("twitterapi", count: 200, maxId: new("900"), sinceId: new("100"));
191 public async Task StatusesShow_Test()
193 var mock = new Mock<IApiConnectionLegacy>();
195 x.GetAsync<TwitterStatus>(
196 new Uri("statuses/show.json", UriKind.Relative),
197 new Dictionary<string, string>
200 { "include_entities", "true" },
201 { "include_ext_alt_text", "true" },
202 { "tweet_mode", "extended" },
204 "/statuses/show/:id")
206 .ReturnsAsync(new TwitterStatus { Id = 100L });
208 using var twitterApi = new TwitterApi();
209 twitterApi.ApiConnection = mock.Object;
211 await twitterApi.StatusesShow(statusId: new("100"));
217 public async Task StatusesLookup_Test()
219 var mock = new Mock<IApiConnectionLegacy>();
221 x.GetAsync<TwitterStatus[]>(
222 new Uri("statuses/lookup.json", UriKind.Relative),
223 new Dictionary<string, string>
226 { "include_entities", "true" },
227 { "include_ext_alt_text", "true" },
228 { "tweet_mode", "extended" },
233 .ReturnsAsync(Array.Empty<TwitterStatus>());
235 using var twitterApi = new TwitterApi();
236 twitterApi.ApiConnection = mock.Object;
238 await twitterApi.StatusesLookup(statusIds: new[] { "100", "200" });
244 public async Task StatusesUpdate_Test()
246 var mock = new Mock<IApiConnectionLegacy>();
248 x.PostLazyAsync<TwitterStatus>(
249 new Uri("statuses/update.json", UriKind.Relative),
250 new Dictionary<string, string>
252 { "status", "hogehoge" },
253 { "include_entities", "true" },
254 { "include_ext_alt_text", "true" },
255 { "tweet_mode", "extended" },
256 { "in_reply_to_status_id", "100" },
257 { "media_ids", "10,20" },
258 { "auto_populate_reply_metadata", "true" },
259 { "exclude_reply_user_ids", "100,200" },
260 { "attachment_url", "https://twitter.com/twitterapi/status/22634515958" },
263 .ReturnsAsync(LazyJson.Create(new TwitterStatus()));
265 using var twitterApi = new TwitterApi();
266 twitterApi.ApiConnection = mock.Object;
268 await twitterApi.StatusesUpdate(
270 replyToId: new("100"),
271 mediaIds: new[] { 10L, 20L },
272 autoPopulateReplyMetadata: true,
273 excludeReplyUserIds: new[] { 100L, 200L },
274 attachmentUrl: "https://twitter.com/twitterapi/status/22634515958"
282 public async Task StatusesUpdate_ExcludeReplyUserIdsEmptyTest()
284 var mock = new Mock<IApiConnectionLegacy>();
286 x.PostLazyAsync<TwitterStatus>(
287 new Uri("statuses/update.json", UriKind.Relative),
288 new Dictionary<string, string>
290 { "status", "hogehoge" },
291 { "include_entities", "true" },
292 { "include_ext_alt_text", "true" },
293 { "tweet_mode", "extended" },
294 // exclude_reply_user_ids は空の場合には送信されない
297 .ReturnsAsync(LazyJson.Create(new TwitterStatus()));
299 using var twitterApi = new TwitterApi();
300 twitterApi.ApiConnection = mock.Object;
302 await twitterApi.StatusesUpdate("hogehoge", replyToId: null, mediaIds: null, excludeReplyUserIds: Array.Empty<long>())
309 public async Task StatusesDestroy_Test()
311 var mock = new Mock<IApiConnectionLegacy>();
313 x.PostLazyAsync<TwitterStatus>(
314 new Uri("statuses/destroy.json", UriKind.Relative),
315 new Dictionary<string, string> { { "id", "100" } })
317 .ReturnsAsync(LazyJson.Create(new TwitterStatus { Id = 100L }));
319 using var twitterApi = new TwitterApi();
320 twitterApi.ApiConnection = mock.Object;
322 await twitterApi.StatusesDestroy(statusId: new("100"))
329 public async Task StatusesRetweet_Test()
331 var mock = new Mock<IApiConnectionLegacy>();
333 x.PostLazyAsync<TwitterStatus>(
334 new Uri("statuses/retweet.json", UriKind.Relative),
335 new Dictionary<string, string>
338 { "include_entities", "true" },
339 { "include_ext_alt_text", "true" },
340 { "tweet_mode", "extended" },
343 .ReturnsAsync(LazyJson.Create(new TwitterStatus()));
345 using var twitterApi = new TwitterApi();
346 twitterApi.ApiConnection = mock.Object;
348 await twitterApi.StatusesRetweet(new("100"))
355 public async Task SearchTweets_Test()
357 var mock = new Mock<IApiConnectionLegacy>();
359 x.GetAsync<TwitterSearchResult>(
360 new Uri("search/tweets.json", UriKind.Relative),
361 new Dictionary<string, string>
363 { "q", "from:twitterapi" },
364 { "result_type", "recent" },
365 { "include_entities", "true" },
366 { "include_ext_alt_text", "true" },
367 { "tweet_mode", "extended" },
371 { "since_id", "100" },
375 .ReturnsAsync(new TwitterSearchResult());
377 using var twitterApi = new TwitterApi();
378 twitterApi.ApiConnection = mock.Object;
380 await twitterApi.SearchTweets("from:twitterapi", "en", count: 200, maxId: new("900"), sinceId: new("100"));
386 public async Task ListsOwnerships_Test()
388 var mock = new Mock<IApiConnectionLegacy>();
390 x.GetAsync<TwitterLists>(
391 new Uri("lists/ownerships.json", UriKind.Relative),
392 new Dictionary<string, string>
394 { "screen_name", "twitterapi" },
400 .ReturnsAsync(new TwitterLists());
402 using var twitterApi = new TwitterApi();
403 twitterApi.ApiConnection = mock.Object;
405 await twitterApi.ListsOwnerships("twitterapi", cursor: -1L, count: 100);
411 public async Task ListsSubscriptions_Test()
413 var mock = new Mock<IApiConnectionLegacy>();
415 x.GetAsync<TwitterLists>(
416 new Uri("lists/subscriptions.json", UriKind.Relative),
417 new Dictionary<string, string>
419 { "screen_name", "twitterapi" },
423 "/lists/subscriptions")
425 .ReturnsAsync(new TwitterLists());
427 using var twitterApi = new TwitterApi();
428 twitterApi.ApiConnection = mock.Object;
430 await twitterApi.ListsSubscriptions("twitterapi", cursor: -1L, count: 100);
436 public async Task ListsMemberships_Test()
438 var mock = new Mock<IApiConnectionLegacy>();
440 x.GetAsync<TwitterLists>(
441 new Uri("lists/memberships.json", UriKind.Relative),
442 new Dictionary<string, string>
444 { "screen_name", "twitterapi" },
447 { "filter_to_owned_lists", "true" },
449 "/lists/memberships")
451 .ReturnsAsync(new TwitterLists());
453 using var twitterApi = new TwitterApi();
454 twitterApi.ApiConnection = mock.Object;
456 await twitterApi.ListsMemberships("twitterapi", cursor: -1L, count: 100, filterToOwnedLists: true);
462 public async Task ListsCreate_Test()
464 var mock = new Mock<IApiConnectionLegacy>();
466 x.PostLazyAsync<TwitterList>(
467 new Uri("lists/create.json", UriKind.Relative),
468 new Dictionary<string, string>
470 { "name", "hogehoge" },
471 { "description", "aaaa" },
472 { "mode", "private" },
475 .ReturnsAsync(LazyJson.Create(new TwitterList()));
477 using var twitterApi = new TwitterApi();
478 twitterApi.ApiConnection = mock.Object;
480 await twitterApi.ListsCreate("hogehoge", description: "aaaa", @private: true)
487 public async Task ListsUpdate_Test()
489 var mock = new Mock<IApiConnectionLegacy>();
491 x.PostLazyAsync<TwitterList>(
492 new Uri("lists/update.json", UriKind.Relative),
493 new Dictionary<string, string>
495 { "list_id", "12345" },
496 { "name", "hogehoge" },
497 { "description", "aaaa" },
498 { "mode", "private" },
501 .ReturnsAsync(LazyJson.Create(new TwitterList()));
503 using var twitterApi = new TwitterApi();
504 twitterApi.ApiConnection = mock.Object;
506 await twitterApi.ListsUpdate(12345L, name: "hogehoge", description: "aaaa", @private: true)
513 public async Task ListsDestroy_Test()
515 var mock = new Mock<IApiConnectionLegacy>();
517 x.PostLazyAsync<TwitterList>(
518 new Uri("lists/destroy.json", UriKind.Relative),
519 new Dictionary<string, string>
521 { "list_id", "12345" },
524 .ReturnsAsync(LazyJson.Create(new TwitterList()));
526 using var twitterApi = new TwitterApi();
527 twitterApi.ApiConnection = mock.Object;
529 await twitterApi.ListsDestroy(12345L)
536 public async Task ListsStatuses_Test()
538 var mock = new Mock<IApiConnectionLegacy>();
540 x.GetAsync<TwitterStatus[]>(
541 new Uri("lists/statuses.json", UriKind.Relative),
542 new Dictionary<string, string>
544 { "list_id", "12345" },
545 { "include_entities", "true" },
546 { "include_ext_alt_text", "true" },
547 { "tweet_mode", "extended" },
550 { "since_id", "100" },
551 { "include_rts", "true" },
555 .ReturnsAsync(Array.Empty<TwitterStatus>());
557 using var twitterApi = new TwitterApi();
558 twitterApi.ApiConnection = mock.Object;
560 await twitterApi.ListsStatuses(12345L, count: 200, maxId: new("900"), sinceId: new("100"), includeRTs: true);
566 public async Task ListsMembers_Test()
568 var mock = new Mock<IApiConnectionLegacy>();
570 x.GetAsync<TwitterUsers>(
571 new Uri("lists/members.json", UriKind.Relative),
572 new Dictionary<string, string>
574 { "list_id", "12345" },
575 { "include_entities", "true" },
576 { "include_ext_alt_text", "true" },
577 { "tweet_mode", "extended" },
582 .ReturnsAsync(new TwitterUsers());
584 using var twitterApi = new TwitterApi();
585 twitterApi.ApiConnection = mock.Object;
587 await twitterApi.ListsMembers(12345L, cursor: -1);
593 public async Task ListsMembersShow_Test()
595 var mock = new Mock<IApiConnectionLegacy>();
597 x.GetAsync<TwitterUser>(
598 new Uri("lists/members/show.json", UriKind.Relative),
599 new Dictionary<string, string>
601 { "list_id", "12345" },
602 { "screen_name", "twitterapi" },
603 { "include_entities", "true" },
604 { "include_ext_alt_text", "true" },
605 { "tweet_mode", "extended" },
607 "/lists/members/show")
609 .ReturnsAsync(new TwitterUser());
611 using var twitterApi = new TwitterApi();
612 twitterApi.ApiConnection = mock.Object;
614 await twitterApi.ListsMembersShow(12345L, "twitterapi");
620 public async Task ListsMembersCreate_Test()
622 var mock = new Mock<IApiConnectionLegacy>();
624 x.PostLazyAsync<TwitterUser>(
625 new Uri("lists/members/create.json", UriKind.Relative),
626 new Dictionary<string, string>
628 { "list_id", "12345" },
629 { "screen_name", "twitterapi" },
630 { "include_entities", "true" },
631 { "include_ext_alt_text", "true" },
632 { "tweet_mode", "extended" },
635 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
637 using var twitterApi = new TwitterApi();
638 twitterApi.ApiConnection = mock.Object;
640 await twitterApi.ListsMembersCreate(12345L, "twitterapi")
647 public async Task ListsMembersDestroy_Test()
649 var mock = new Mock<IApiConnectionLegacy>();
651 x.PostLazyAsync<TwitterUser>(
652 new Uri("lists/members/destroy.json", UriKind.Relative),
653 new Dictionary<string, string>
655 { "list_id", "12345" },
656 { "screen_name", "twitterapi" },
657 { "include_entities", "true" },
658 { "include_ext_alt_text", "true" },
659 { "tweet_mode", "extended" },
662 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
664 using var twitterApi = new TwitterApi();
665 twitterApi.ApiConnection = mock.Object;
667 await twitterApi.ListsMembersDestroy(12345L, "twitterapi")
674 public async Task DirectMessagesEventsList_Test()
676 var mock = new Mock<IApiConnectionLegacy>();
678 x.GetAsync<TwitterMessageEventList>(
679 new Uri("direct_messages/events/list.json", UriKind.Relative),
680 new Dictionary<string, string>
683 { "cursor", "12345abcdefg" },
685 "/direct_messages/events/list")
687 .ReturnsAsync(new TwitterMessageEventList());
689 using var twitterApi = new TwitterApi();
690 twitterApi.ApiConnection = mock.Object;
692 await twitterApi.DirectMessagesEventsList(count: 50, cursor: "12345abcdefg");
698 public async Task DirectMessagesEventsNew_Test()
700 var requestJson = """
703 "type": "message_create",
706 "recipient_id": "12345"
722 var mock = this.CreateApiConnectionMock<PostJsonRequest>(r =>
724 Assert.Equal(new("direct_messages/events/new.json", UriKind.Relative), r.RequestUri);
725 Assert.Equal(requestJson, r.JsonString);
728 using var twitterApi = new TwitterApi();
729 twitterApi.ApiConnection = mock.Object;
731 await twitterApi.DirectMessagesEventsNew(recipientId: 12345L, text: "hogehoge", mediaId: 67890L);
737 public async Task DirectMessagesEventsDestroy_Test()
739 var mock = this.CreateApiConnectionMock<DeleteRequest>(r =>
741 Assert.Equal(new("direct_messages/events/destroy.json", UriKind.Relative), r.RequestUri);
742 var expectedQuery = new Dictionary<string, string>
746 Assert.Equal(expectedQuery, r.Query);
749 using var twitterApi = new TwitterApi();
750 twitterApi.ApiConnection = mock.Object;
752 await twitterApi.DirectMessagesEventsDestroy(eventId: new("100"));
758 public async Task UsersShow_Test()
760 var mock = new Mock<IApiConnectionLegacy>();
762 x.GetAsync<TwitterUser>(
763 new Uri("users/show.json", UriKind.Relative),
764 new Dictionary<string, string>
766 { "screen_name", "twitterapi" },
767 { "include_entities", "true" },
768 { "include_ext_alt_text", "true" },
769 { "tweet_mode", "extended" },
773 .ReturnsAsync(new TwitterUser { ScreenName = "twitterapi" });
775 using var twitterApi = new TwitterApi();
776 twitterApi.ApiConnection = mock.Object;
778 await twitterApi.UsersShow(screenName: "twitterapi");
784 public async Task UsersLookup_Test()
786 var mock = new Mock<IApiConnectionLegacy>();
788 x.GetAsync<TwitterUser[]>(
789 new Uri("users/lookup.json", UriKind.Relative),
790 new Dictionary<string, string>
792 { "user_id", "11111,22222" },
793 { "include_entities", "true" },
794 { "include_ext_alt_text", "true" },
795 { "tweet_mode", "extended" },
799 .ReturnsAsync(Array.Empty<TwitterUser>());
801 using var twitterApi = new TwitterApi();
802 twitterApi.ApiConnection = mock.Object;
804 await twitterApi.UsersLookup(userIds: new[] { "11111", "22222" });
810 public async Task UsersReportSpam_Test()
812 var mock = new Mock<IApiConnectionLegacy>();
814 x.PostLazyAsync<TwitterUser>(
815 new Uri("users/report_spam.json", UriKind.Relative),
816 new Dictionary<string, string>
818 { "screen_name", "twitterapi" },
819 { "tweet_mode", "extended" },
822 .ReturnsAsync(LazyJson.Create(new TwitterUser { ScreenName = "twitterapi" }));
824 using var twitterApi = new TwitterApi();
825 twitterApi.ApiConnection = mock.Object;
827 await twitterApi.UsersReportSpam(screenName: "twitterapi")
834 public async Task FavoritesList_Test()
836 var mock = new Mock<IApiConnectionLegacy>();
838 x.GetAsync<TwitterStatus[]>(
839 new Uri("favorites/list.json", UriKind.Relative),
840 new Dictionary<string, string>
842 { "include_entities", "true" },
843 { "include_ext_alt_text", "true" },
844 { "tweet_mode", "extended" },
847 { "since_id", "100" },
851 .ReturnsAsync(Array.Empty<TwitterStatus>());
853 using var twitterApi = new TwitterApi();
854 twitterApi.ApiConnection = mock.Object;
856 await twitterApi.FavoritesList(200, maxId: 900L, sinceId: 100L);
862 public async Task FavoritesCreate_Test()
864 var mock = new Mock<IApiConnectionLegacy>();
866 x.PostLazyAsync<TwitterStatus>(
867 new Uri("favorites/create.json", UriKind.Relative),
868 new Dictionary<string, string>
871 { "tweet_mode", "extended" },
874 .ReturnsAsync(LazyJson.Create(new TwitterStatus { Id = 100L }));
876 using var twitterApi = new TwitterApi();
877 twitterApi.ApiConnection = mock.Object;
879 await twitterApi.FavoritesCreate(statusId: new("100"))
886 public async Task FavoritesDestroy_Test()
888 var mock = new Mock<IApiConnectionLegacy>();
890 x.PostLazyAsync<TwitterStatus>(
891 new Uri("favorites/destroy.json", UriKind.Relative),
892 new Dictionary<string, string>
895 { "tweet_mode", "extended" },
898 .ReturnsAsync(LazyJson.Create(new TwitterStatus { Id = 100L }));
900 using var twitterApi = new TwitterApi();
901 twitterApi.ApiConnection = mock.Object;
903 await twitterApi.FavoritesDestroy(statusId: new("100"))
910 public async Task FriendshipsShow_Test()
912 var mock = new Mock<IApiConnectionLegacy>();
914 x.GetAsync<TwitterFriendship>(
915 new Uri("friendships/show.json", UriKind.Relative),
916 new Dictionary<string, string> { { "source_screen_name", "twitter" }, { "target_screen_name", "twitterapi" } },
919 .ReturnsAsync(new TwitterFriendship());
921 using var twitterApi = new TwitterApi();
922 twitterApi.ApiConnection = mock.Object;
924 await twitterApi.FriendshipsShow(sourceScreenName: "twitter", targetScreenName: "twitterapi");
930 public async Task FriendshipsCreate_Test()
932 var mock = new Mock<IApiConnectionLegacy>();
934 x.PostLazyAsync<TwitterFriendship>(
935 new Uri("friendships/create.json", UriKind.Relative),
936 new Dictionary<string, string> { { "screen_name", "twitterapi" } })
938 .ReturnsAsync(LazyJson.Create(new TwitterFriendship()));
940 using var twitterApi = new TwitterApi();
941 twitterApi.ApiConnection = mock.Object;
943 await twitterApi.FriendshipsCreate(screenName: "twitterapi")
950 public async Task FriendshipsDestroy_Test()
952 var mock = new Mock<IApiConnectionLegacy>();
954 x.PostLazyAsync<TwitterFriendship>(
955 new Uri("friendships/destroy.json", UriKind.Relative),
956 new Dictionary<string, string> { { "screen_name", "twitterapi" } })
958 .ReturnsAsync(LazyJson.Create(new TwitterFriendship()));
960 using var twitterApi = new TwitterApi();
961 twitterApi.ApiConnection = mock.Object;
963 await twitterApi.FriendshipsDestroy(screenName: "twitterapi")
970 public async Task NoRetweetIds_Test()
972 var mock = new Mock<IApiConnectionLegacy>();
975 new Uri("friendships/no_retweets/ids.json", UriKind.Relative),
977 "/friendships/no_retweets/ids")
979 .ReturnsAsync(Array.Empty<long>());
981 using var twitterApi = new TwitterApi();
982 twitterApi.ApiConnection = mock.Object;
984 await twitterApi.NoRetweetIds();
990 public async Task FollowersIds_Test()
992 var mock = new Mock<IApiConnectionLegacy>();
994 x.GetAsync<TwitterIds>(
995 new Uri("followers/ids.json", UriKind.Relative),
996 new Dictionary<string, string> { { "cursor", "-1" } },
999 .ReturnsAsync(new TwitterIds());
1001 using var twitterApi = new TwitterApi();
1002 twitterApi.ApiConnection = mock.Object;
1004 await twitterApi.FollowersIds(cursor: -1L);
1010 public async Task MutesUsersIds_Test()
1012 var mock = new Mock<IApiConnectionLegacy>();
1014 x.GetAsync<TwitterIds>(
1015 new Uri("mutes/users/ids.json", UriKind.Relative),
1016 new Dictionary<string, string> { { "cursor", "-1" } },
1019 .ReturnsAsync(new TwitterIds());
1021 using var twitterApi = new TwitterApi();
1022 twitterApi.ApiConnection = mock.Object;
1024 await twitterApi.MutesUsersIds(cursor: -1L);
1030 public async Task BlocksIds_Test()
1032 var mock = new Mock<IApiConnectionLegacy>();
1034 x.GetAsync<TwitterIds>(
1035 new Uri("blocks/ids.json", UriKind.Relative),
1036 new Dictionary<string, string> { { "cursor", "-1" } },
1039 .ReturnsAsync(new TwitterIds());
1041 using var twitterApi = new TwitterApi();
1042 twitterApi.ApiConnection = mock.Object;
1044 await twitterApi.BlocksIds(cursor: -1L);
1050 public async Task BlocksCreate_Test()
1052 var mock = new Mock<IApiConnectionLegacy>();
1054 x.PostLazyAsync<TwitterUser>(
1055 new Uri("blocks/create.json", UriKind.Relative),
1056 new Dictionary<string, string>
1058 { "screen_name", "twitterapi" },
1059 { "tweet_mode", "extended" },
1062 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
1064 using var twitterApi = new TwitterApi();
1065 twitterApi.ApiConnection = mock.Object;
1067 await twitterApi.BlocksCreate(screenName: "twitterapi")
1074 public async Task BlocksDestroy_Test()
1076 var mock = new Mock<IApiConnectionLegacy>();
1078 x.PostLazyAsync<TwitterUser>(
1079 new Uri("blocks/destroy.json", UriKind.Relative),
1080 new Dictionary<string, string>
1082 { "screen_name", "twitterapi" },
1083 { "tweet_mode", "extended" },
1086 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
1088 using var twitterApi = new TwitterApi();
1089 twitterApi.ApiConnection = mock.Object;
1091 await twitterApi.BlocksDestroy(screenName: "twitterapi")
1098 public async Task AccountVerifyCredentials_Test()
1100 var mock = new Mock<IApiConnectionLegacy>();
1102 x.GetAsync<TwitterUser>(
1103 new Uri("account/verify_credentials.json", UriKind.Relative),
1104 new Dictionary<string, string>
1106 { "include_entities", "true" },
1107 { "include_ext_alt_text", "true" },
1108 { "tweet_mode", "extended" },
1110 "/account/verify_credentials")
1112 .ReturnsAsync(new TwitterUser
1115 ScreenName = "opentween",
1118 using var twitterApi = new TwitterApi();
1119 twitterApi.ApiConnection = mock.Object;
1121 await twitterApi.AccountVerifyCredentials();
1123 Assert.Equal(100L, twitterApi.CurrentUserId);
1124 Assert.Equal("opentween", twitterApi.CurrentScreenName);
1130 public async Task AccountUpdateProfile_Test()
1132 var mock = new Mock<IApiConnectionLegacy>();
1134 x.PostLazyAsync<TwitterUser>(
1135 new Uri("account/update_profile.json", UriKind.Relative),
1136 new Dictionary<string, string>
1138 { "include_entities", "true" },
1139 { "include_ext_alt_text", "true" },
1140 { "tweet_mode", "extended" },
1142 { "url", "http://example.com/" },
1143 { "location", "Location" },
1144 { "description", "<script>alert(1)</script>" },
1147 .ReturnsAsync(LazyJson.Create(new TwitterUser()));
1149 using var twitterApi = new TwitterApi();
1150 twitterApi.ApiConnection = mock.Object;
1152 await twitterApi.AccountUpdateProfile(name: "Name", url: "http://example.com/", location: "Location", description: "<script>alert(1)</script>")
1159 public async Task AccountUpdateProfileImage_Test()
1161 using var image = TestUtils.CreateDummyImage();
1162 using var media = new MemoryImageMediaItem(image);
1164 var mock = this.CreateApiConnectionMock<PostMultipartRequest>(r =>
1166 Assert.Equal(new("account/update_profile_image.json", UriKind.Relative), r.RequestUri);
1167 var expectedQuery = new Dictionary<string, string>
1169 ["include_entities"] = "true",
1170 ["include_ext_alt_text"] = "true",
1171 ["tweet_mode"] = "extended",
1173 Assert.Equal(expectedQuery, r.Query);
1174 var expectedMedia = new Dictionary<string, IMediaItem>
1178 Assert.Equal(expectedMedia, r.Media);
1181 using var twitterApi = new TwitterApi();
1182 twitterApi.ApiConnection = mock.Object;
1184 await twitterApi.AccountUpdateProfileImage(media)
1191 public async Task ApplicationRateLimitStatus_Test()
1193 var mock = new Mock<IApiConnectionLegacy>();
1195 x.GetAsync<TwitterRateLimits>(
1196 new Uri("application/rate_limit_status.json", UriKind.Relative),
1198 "/application/rate_limit_status")
1200 .ReturnsAsync(new TwitterRateLimits());
1202 using var twitterApi = new TwitterApi();
1203 twitterApi.ApiConnection = mock.Object;
1205 await twitterApi.ApplicationRateLimitStatus();
1211 public async Task Configuration_Test()
1213 var mock = new Mock<IApiConnectionLegacy>();
1215 x.GetAsync<TwitterConfiguration>(
1216 new Uri("help/configuration.json", UriKind.Relative),
1218 "/help/configuration")
1220 .ReturnsAsync(new TwitterConfiguration());
1222 using var twitterApi = new TwitterApi();
1223 twitterApi.ApiConnection = mock.Object;
1225 await twitterApi.Configuration();
1231 public async Task MediaUploadInit_Test()
1233 var mock = new Mock<IApiConnectionLegacy>();
1235 x.PostLazyAsync<TwitterUploadMediaInit>(
1236 new Uri("https://upload.twitter.com/1.1/media/upload.json", UriKind.Absolute),
1237 new Dictionary<string, string>
1239 { "command", "INIT" },
1240 { "total_bytes", "123456" },
1241 { "media_type", "image/png" },
1242 { "media_category", "dm_image" },
1245 .ReturnsAsync(LazyJson.Create(new TwitterUploadMediaInit()));
1247 using var twitterApi = new TwitterApi();
1248 twitterApi.ApiConnection = mock.Object;
1250 await twitterApi.MediaUploadInit(totalBytes: 123456L, mediaType: "image/png", mediaCategory: "dm_image")
1257 public async Task MediaUploadAppend_Test()
1259 using var image = TestUtils.CreateDummyImage();
1260 using var media = new MemoryImageMediaItem(image);
1262 var mock = this.CreateApiConnectionMock<PostMultipartRequest>(r =>
1264 Assert.Equal(new("https://upload.twitter.com/1.1/media/upload.json"), r.RequestUri);
1265 var expectedQuery = new Dictionary<string, string>
1267 ["command"] = "APPEND",
1268 ["media_id"] = "11111",
1269 ["segment_index"] = "1",
1271 Assert.Equal(expectedQuery, r.Query);
1272 var expectedMedia = new Dictionary<string, IMediaItem>
1276 Assert.Equal(expectedMedia, r.Media);
1279 using var twitterApi = new TwitterApi();
1280 twitterApi.ApiConnection = mock.Object;
1282 await twitterApi.MediaUploadAppend(mediaId: 11111L, segmentIndex: 1, media: media);
1288 public async Task MediaUploadFinalize_Test()
1290 var mock = new Mock<IApiConnectionLegacy>();
1292 x.PostLazyAsync<TwitterUploadMediaResult>(
1293 new Uri("https://upload.twitter.com/1.1/media/upload.json", UriKind.Absolute),
1294 new Dictionary<string, string>
1296 { "command", "FINALIZE" },
1297 { "media_id", "11111" },
1300 .ReturnsAsync(LazyJson.Create(new TwitterUploadMediaResult()));
1302 using var twitterApi = new TwitterApi();
1303 twitterApi.ApiConnection = mock.Object;
1305 await twitterApi.MediaUploadFinalize(mediaId: 11111L)
1312 public async Task MediaUploadStatus_Test()
1314 var mock = new Mock<IApiConnectionLegacy>();
1316 x.GetAsync<TwitterUploadMediaResult>(
1317 new Uri("https://upload.twitter.com/1.1/media/upload.json", UriKind.Absolute),
1318 new Dictionary<string, string>
1320 { "command", "STATUS" },
1321 { "media_id", "11111" },
1325 .ReturnsAsync(new TwitterUploadMediaResult());
1327 using var twitterApi = new TwitterApi();
1328 twitterApi.ApiConnection = mock.Object;
1330 await twitterApi.MediaUploadStatus(mediaId: 11111L);
1336 public async Task MediaMetadataCreate_Test()
1338 var mock = this.CreateApiConnectionMock<PostJsonRequest>(r =>
1340 Assert.Equal(new("https://upload.twitter.com/1.1/media/metadata/create.json"), r.RequestUri);
1341 Assert.Equal("""{"media_id": "12345", "alt_text": {"text": "hogehoge"}}""", r.JsonString);
1344 using var twitterApi = new TwitterApi();
1345 twitterApi.ApiConnection = mock.Object;
1347 await twitterApi.MediaMetadataCreate(mediaId: 12345L, altText: "hogehoge");