Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IApiConnectionLegacy の一部メソッドを IApiConnection に移行 #278

Merged
merged 7 commits into from
Dec 11, 2023
40 changes: 26 additions & 14 deletions OpenTween.Tests/Api/TwitterApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -674,8 +675,9 @@ public async Task DirectMessagesEventsList_Test()
[Fact]
public async Task DirectMessagesEventsNew_Test()
{
using var responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
var mock = new Mock<IApiConnectionLegacy>();
var responseText = """
var requestJson = """
{
"event": {
"type": "message_create",
Expand All @@ -697,11 +699,14 @@ public async Task DirectMessagesEventsNew_Test()
}
""";
mock.Setup(x =>
x.PostJsonAsync<TwitterMessageEventSingle>(
new Uri("direct_messages/events/new.json", UriKind.Relative),
responseText)
x.SendAsync(
It.Is<PostJsonRequest>(r =>
r.RequestUri == new Uri("direct_messages/events/new.json", UriKind.Relative) &&
r.JsonString == requestJson
)
)
)
.ReturnsAsync(LazyJson.Create(new TwitterMessageEventSingle()));
.ReturnsAsync(new ApiResponse(responseMessage));

using var twitterApi = new TwitterApi();
twitterApi.ApiConnection = mock.Object;
Expand All @@ -716,10 +721,15 @@ public async Task DirectMessagesEventsDestroy_Test()
{
var mock = new Mock<IApiConnectionLegacy>();
mock.Setup(x =>
x.DeleteAsync(
new Uri("direct_messages/events/destroy.json?id=100", UriKind.Relative))
)
.Returns(Task.CompletedTask);
x.SendAsync(
It.Is<DeleteRequest>(r =>
r.RequestUri == new Uri("direct_messages/events/destroy.json", UriKind.Relative) &&
r.Query != null &&
r.Query.Count == 1 &&
r.Query["id"] == "100"
)
)
);

using var twitterApi = new TwitterApi();
twitterApi.ApiConnection = mock.Object;
Expand Down Expand Up @@ -1304,11 +1314,13 @@ public async Task MediaMetadataCreate_Test()
{
var mock = new Mock<IApiConnectionLegacy>();
mock.Setup(x =>
x.PostJsonAsync(
new Uri("https://upload.twitter.com/1.1/media/metadata/create.json", UriKind.Absolute),
"""{"media_id": "12345", "alt_text": {"text": "hogehoge"}}""")
)
.ReturnsAsync("");
x.SendAsync(
It.Is<PostJsonRequest>(r =>
r.RequestUri == new Uri("https://upload.twitter.com/1.1/media/metadata/create.json") &&
r.JsonString == """{"media_id": "12345", "alt_text": {"text": "hogehoge"}}"""
)
)
);

using var twitterApi = new TwitterApi();
twitterApi.ApiConnection = mock.Object;
Expand Down
50 changes: 50 additions & 0 deletions OpenTween.Tests/Connection/DeleteRequestTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// OpenTween - Client of Twitter
// Copyright (c) 2023 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
// All rights reserved.
//
// This file is part of OpenTween.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
// Boston, MA 02110-1301, USA.

using System;
using System.Collections.Generic;
using System.Net.Http;
using Xunit;

namespace OpenTween.Connection
{
public class DeleteRequestTest
{
[Fact]
public void CreateMessage_Test()
{
var request = new DeleteRequest
{
RequestUri = new("hoge/aaa.json", UriKind.Relative),
Query = new Dictionary<string, string>
{
["id"] = "12345",
},
};

var baseUri = new Uri("https://example.com/v1/");
using var requestMessage = request.CreateMessage(baseUri);

Assert.Equal(HttpMethod.Delete, requestMessage.Method);
Assert.Equal(new("https://example.com/v1/hoge/aaa.json?id=12345"), requestMessage.RequestUri);
}
}
}
139 changes: 0 additions & 139 deletions OpenTween.Tests/Connection/TwitterApiConnectionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,52 +280,6 @@ public async Task SendAsync_ErrorJsonTest()
Assert.Equal(0, mockHandler.QueueCount);
}

[Fact]
public async Task GetStreamAsync_Test()
{
using var mockHandler = new HttpMessageHandlerMock();
using var http = new HttpClient(mockHandler);
using var apiConnection = new TwitterApiConnection();
using var image = TestUtils.CreateDummyImage();
apiConnection.Http = http;

mockHandler.Enqueue(x =>
{
Assert.Equal(HttpMethod.Get, x.Method);
Assert.Equal("https://api.twitter.com/1.1/hoge/tetete.json",
x.RequestUri.GetLeftPart(UriPartial.Path));

var query = HttpUtility.ParseQueryString(x.RequestUri.Query);

Assert.Equal("1111", query["aaaa"]);
Assert.Equal("2222", query["bbbb"]);

return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(image.Stream.ToArray()),
};
});

var endpoint = new Uri("hoge/tetete.json", UriKind.Relative);
var param = new Dictionary<string, string>
{
["aaaa"] = "1111",
["bbbb"] = "2222",
};

var stream = await apiConnection.GetStreamAsync(endpoint, param);

using (var memoryStream = new MemoryStream())
{
// 内容の比較のために MemoryStream にコピー
await stream.CopyToAsync(memoryStream);

Assert.Equal(image.Stream.ToArray(), memoryStream.ToArray());
}

Assert.Equal(0, mockHandler.QueueCount);
}

[Fact]
public async Task PostLazyAsync_Test()
{
Expand Down Expand Up @@ -481,99 +435,6 @@ public async Task PostLazyAsync_Multipart_NullTest()
Assert.Equal(0, mockHandler.QueueCount);
}

[Fact]
public async Task PostJsonAsync_Test()
{
using var mockHandler = new HttpMessageHandlerMock();
using var http = new HttpClient(mockHandler);
using var apiConnection = new TwitterApiConnection();
apiConnection.Http = http;

mockHandler.Enqueue(async x =>
{
Assert.Equal(HttpMethod.Post, x.Method);
Assert.Equal("https://api.twitter.com/1.1/hoge/tetete.json",
x.RequestUri.AbsoluteUri);

Assert.Equal("application/json; charset=utf-8", x.Content.Headers.ContentType.ToString());

var body = await x.Content.ReadAsStringAsync();

Assert.Equal("""{"aaaa": 1111}""", body);

return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(@"{""ok"":true}"),
};
});

var endpoint = new Uri("hoge/tetete.json", UriKind.Relative);

var response = await apiConnection.PostJsonAsync(endpoint, """{"aaaa": 1111}""");

Assert.Equal(@"{""ok"":true}", response);
Assert.Equal(0, mockHandler.QueueCount);
}

[Fact]
public async Task PostJsonAsync_T_Test()
{
using var mockHandler = new HttpMessageHandlerMock();
using var http = new HttpClient(mockHandler);
using var apiConnection = new TwitterApiConnection();
apiConnection.Http = http;

mockHandler.Enqueue(async x =>
{
Assert.Equal(HttpMethod.Post, x.Method);
Assert.Equal("https://api.twitter.com/1.1/hoge/tetete.json",
x.RequestUri.AbsoluteUri);

Assert.Equal("application/json; charset=utf-8", x.Content.Headers.ContentType.ToString());

var body = await x.Content.ReadAsStringAsync();

Assert.Equal("""{"aaaa": 1111}""", body);

return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("\"hogehoge\""),
};
});

var endpoint = new Uri("hoge/tetete.json", UriKind.Relative);
var response = await apiConnection.PostJsonAsync<string>(endpoint, """{"aaaa": 1111}""");
var result = await response.LoadJsonAsync();

Assert.Equal("hogehoge", result);

Assert.Equal(0, mockHandler.QueueCount);
}

[Fact]
public async Task DeleteAsync_Test()
{
using var mockHandler = new HttpMessageHandlerMock();
using var http = new HttpClient(mockHandler);
using var apiConnection = new TwitterApiConnection();
apiConnection.Http = http;

mockHandler.Enqueue(x =>
{
Assert.Equal(HttpMethod.Delete, x.Method);
Assert.Equal("https://api.twitter.com/1.1/hoge/tetete.json",
x.RequestUri.AbsoluteUri);

return new HttpResponseMessage(HttpStatusCode.NoContent);
});

var endpoint = new Uri("hoge/tetete.json", UriKind.Relative);

await apiConnection.DeleteAsync(endpoint);

Assert.Equal(0, mockHandler.QueueCount);
}

[Fact]
public async Task HandleTimeout_SuccessTest()
{
Expand Down
47 changes: 30 additions & 17 deletions OpenTween/Api/TwitterApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,8 @@ public Task<TwitterMessageEventList> DirectMessagesEventsList(int? count = null,
return this.Connection.GetAsync<TwitterMessageEventList>(endpoint, param, "/direct_messages/events/list");
}

public Task<LazyJson<TwitterMessageEventSingle>> DirectMessagesEventsNew(long recipientId, string text, long? mediaId = null)
public async Task<LazyJson<TwitterMessageEventSingle>> DirectMessagesEventsNew(long recipientId, string text, long? mediaId = null)
{
var endpoint = new Uri("direct_messages/events/new.json", UriKind.Relative);

var attachment = "";
if (mediaId != null)
{
Expand Down Expand Up @@ -458,21 +456,32 @@ public Task<LazyJson<TwitterMessageEventSingle>> DirectMessagesEventsNew(long re
}
""";

return this.Connection.PostJsonAsync<TwitterMessageEventSingle>(endpoint, json);
var request = new PostJsonRequest
{
RequestUri = new("direct_messages/events/new.json", UriKind.Relative),
JsonString = json,
};

var response = await this.Connection.SendAsync(request)
.ConfigureAwait(false);

return response.ReadAsLazyJson<TwitterMessageEventSingle>();
}

public Task DirectMessagesEventsDestroy(TwitterDirectMessageId eventId)
public async Task DirectMessagesEventsDestroy(TwitterDirectMessageId eventId)
{
var endpoint = new Uri("direct_messages/events/destroy.json", UriKind.Relative);
var param = new Dictionary<string, string>
var request = new DeleteRequest
{
["id"] = eventId.Id,
RequestUri = new("direct_messages/events/destroy.json", UriKind.Relative),
Query = new Dictionary<string, string>
{
["id"] = eventId.Id,
},
};

// なぜか application/x-www-form-urlencoded でパラメーターを送ると Bad Request になる謎仕様
endpoint = new Uri(endpoint.OriginalString + "?" + MyCommon.BuildQueryString(param), UriKind.Relative);

return this.Connection.DeleteAsync(endpoint);
await this.Connection.SendAsync(request)
.IgnoreResponse()
.ConfigureAwait(false);
}

public Task<TwitterUser> UsersShow(string screenName)
Expand Down Expand Up @@ -792,14 +801,18 @@ public Task<TwitterUploadMediaResult> MediaUploadStatus(long mediaId)
return this.Connection.GetAsync<TwitterUploadMediaResult>(endpoint, param, endpointName: null);
}

public Task MediaMetadataCreate(long mediaId, string altText)
public async Task MediaMetadataCreate(long mediaId, string altText)
{
var endpoint = new Uri("https://upload.twitter.com/1.1/media/metadata/create.json");

var escapedAltText = JsonUtils.EscapeJsonString(altText);
var json = $$$"""{"media_id": "{{{mediaId}}}", "alt_text": {"text": "{{{escapedAltText}}}"}}""";
var request = new PostJsonRequest
{
RequestUri = new("https://upload.twitter.com/1.1/media/metadata/create.json"),
JsonString = $$$"""{"media_id": "{{{mediaId}}}", "alt_text": {"text": "{{{escapedAltText}}}"}}""",
};

return this.Connection.PostJsonAsync(endpoint, json);
await this.Connection.SendAsync(request)
.IgnoreResponse()
.ConfigureAwait(false);
}

public OAuthEchoHandler CreateOAuthEchoHandler(HttpMessageHandler innerHandler, Uri authServiceProvider, Uri? realm = null)
Expand Down
9 changes: 9 additions & 0 deletions OpenTween/Connection/ApiResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,13 @@ public async Task<string> ReadAsString()
.ConfigureAwait(false);
}
}

public static class ApiResponseTaskExtension
{
public static async Task IgnoreResponse(this Task<ApiResponse> task)
{
using var response = await task.ConfigureAwait(false);
// レスポンスボディを読み込まず破棄する
}
}
}
Loading