OSDN Git Service

C# 8.0 のnull許容参照型を有効化
[opentween/open-tween.git] / OpenTween.Tests / Thumbnail / Services / FoursquareCheckinTest.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2014 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.Globalization;
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;
32 using System.Threading.Tasks;
33 using System.Web;
34 using Moq;
35 using OpenTween.Models;
36 using Xunit;
37 using Xunit.Extensions;
38
39 namespace OpenTween.Thumbnail.Services
40 {
41     public class FoursquareCheckinTest
42     {
43         [Fact]
44         public void UrlPattern_Test()
45         {
46             // 通常のチェックイン URL (www.swarmapp.com/c/***)
47             var match = FoursquareCheckin.UrlPatternRegex.Match("https://www.swarmapp.com/c/xxxxxxxx");
48             Assert.True(match.Success);
49             Assert.Equal("xxxxxxxx", match.Groups["checkin_id"].Value);
50         }
51
52         [Fact]
53         public void LegacyUrlPattern_Test()
54         {
55             // 古い形式の URL (foursquare.com/***/checkin/***?s=***)
56             var match = FoursquareCheckin.LegacyUrlPatternRegex.Match("https://foursquare.com/hogehoge/checkin/xxxxxxxx?s=aaaaaaa");
57             Assert.True(match.Success);
58             Assert.Equal("xxxxxxxx", match.Groups["checkin_id"].Value);
59             Assert.Equal("aaaaaaa", match.Groups["signature"].Value);
60
61             // 古い形式の URL (www.swarmapp.com/***/checkin/***?s=***)
62             match = FoursquareCheckin.LegacyUrlPatternRegex.Match("https://www.swarmapp.com/hogehoge/checkin/xxxxxxxx?s=aaaaaaa");
63             Assert.True(match.Success);
64             Assert.Equal("xxxxxxxx", match.Groups["checkin_id"].Value);
65             Assert.Equal("aaaaaaa", match.Groups["signature"].Value);
66         }
67
68         [Fact]
69         public async Task GetThumbnailInfoAsync_NewUrlTest()
70         {
71             var handler = new HttpMessageHandlerMock();
72             using (var http = new HttpClient(handler))
73             {
74                 var service = new FoursquareCheckin(http);
75
76                 handler.Enqueue(x =>
77                 {
78                     Assert.Equal(HttpMethod.Get, x.Method);
79                     Assert.Equal("https://api.foursquare.com/v2/checkins/resolve",
80                         x.RequestUri.GetLeftPart(UriPartial.Path));
81
82                     var query = HttpUtility.ParseQueryString(x.RequestUri.Query);
83
84                     Assert.Equal(ApplicationSettings.FoursquareClientId, query["client_id"]);
85                     Assert.Equal(ApplicationSettings.FoursquareClientSecret, query["client_secret"]);
86                     Assert.NotNull(query["v"]);
87                     Assert.Equal("xxxxxxxx", query["shortId"]);
88
89                     // リクエストに対するテストなのでレスポンスは適当に返す
90                     return new HttpResponseMessage(HttpStatusCode.NotFound);
91                 });
92
93                 var post = new PostClass
94                 {
95                     PostGeo = null,
96                 };
97
98                 await service.GetThumbnailInfoAsync(
99                     "https://www.swarmapp.com/c/xxxxxxxx",
100                     post, CancellationToken.None);
101
102                 Assert.Equal(0, handler.QueueCount);
103             }
104         }
105
106         [Fact]
107         public async Task GetThumbnailInfoAsync_LegacyUrlTest()
108         {
109             var handler = new HttpMessageHandlerMock();
110             using (var http = new HttpClient(handler))
111             {
112                 var service = new FoursquareCheckin(http);
113
114                 handler.Enqueue(x =>
115                 {
116                     Assert.Equal(HttpMethod.Get, x.Method);
117                     Assert.Equal("https://api.foursquare.com/v2/checkins/xxxxxxxx",
118                         x.RequestUri.GetLeftPart(UriPartial.Path));
119
120                     var query = HttpUtility.ParseQueryString(x.RequestUri.Query);
121
122                     Assert.Equal(ApplicationSettings.FoursquareClientId, query["client_id"]);
123                     Assert.Equal(ApplicationSettings.FoursquareClientSecret, query["client_secret"]);
124                     Assert.NotNull(query["v"]);
125                     Assert.Null(query["signature"]);
126
127                     // リクエストに対するテストなのでレスポンスは適当に返す
128                     return new HttpResponseMessage(HttpStatusCode.NotFound);
129                 });
130
131                 var post = new PostClass
132                 {
133                     PostGeo = null,
134                 };
135
136                 await service.GetThumbnailInfoAsync(
137                     "https://foursquare.com/hogehoge/checkin/xxxxxxxx",
138                     post, CancellationToken.None);
139
140                 Assert.Equal(0, handler.QueueCount);
141             }
142         }
143
144         [Fact]
145         public async Task GetThumbnailInfoAsync_LegacyUrlWithSignatureTest()
146         {
147             var handler = new HttpMessageHandlerMock();
148             using (var http = new HttpClient(handler))
149             {
150                 var service = new FoursquareCheckin(http);
151
152                 handler.Enqueue(x =>
153                 {
154                     Assert.Equal(HttpMethod.Get, x.Method);
155                     Assert.Equal("https://api.foursquare.com/v2/checkins/xxxxxxxx",
156                         x.RequestUri.GetLeftPart(UriPartial.Path));
157
158                     var query = HttpUtility.ParseQueryString(x.RequestUri.Query);
159
160                     Assert.Equal(ApplicationSettings.FoursquareClientId, query["client_id"]);
161                     Assert.Equal(ApplicationSettings.FoursquareClientSecret, query["client_secret"]);
162                     Assert.NotNull(query["v"]);
163                     Assert.Equal("aaaaaaa", query["signature"]);
164
165                     // リクエストに対するテストなのでレスポンスは適当に返す
166                     return new HttpResponseMessage(HttpStatusCode.NotFound);
167                 });
168
169                 var post = new PostClass
170                 {
171                     PostGeo = null,
172                 };
173
174                 await service.GetThumbnailInfoAsync(
175                     "https://foursquare.com/hogehoge/checkin/xxxxxxxx?s=aaaaaaa",
176                     post, CancellationToken.None);
177
178                 Assert.Equal(0, handler.QueueCount);
179             }
180         }
181
182         [Fact]
183         public async Task GetThumbnailInfoAsync_GeoLocatedTweetTest()
184         {
185             var handler = new HttpMessageHandlerMock();
186             using (var http = new HttpClient(handler))
187             {
188                 var service = new FoursquareCheckin(http);
189
190                 handler.Enqueue(x =>
191                 {
192                     // このリクエストは実行されないはず
193                     Assert.True(false);
194                     return new HttpResponseMessage(HttpStatusCode.NotFound);
195                 });
196
197                 // 既にジオタグが付いているツイートに対しては何もしない
198                 var post = new PostClass
199                 {
200                     PostGeo = new PostClass.StatusGeo(134.04693603515625, 34.35067978344854),
201                 };
202
203                 await service.GetThumbnailInfoAsync(
204                     "https://www.swarmapp.com/c/xxxxxxxx",
205                     post, CancellationToken.None);
206
207                 Assert.Equal(1, handler.QueueCount);
208             }
209         }
210
211         [Fact]
212         public void ParseInLocation_Test()
213         {
214             var json = @"{
215   ""meta"": { ""code"": 200 },
216   ""response"": {
217     ""checkin"": {
218       ""id"": ""xxxxxxxxx"",
219       ""type"": ""checkin"",
220       ""venue"": {
221         ""id"": ""4b73dedcf964a5206bbe2de3"",
222         ""name"": ""高松駅 (Takamatsu Sta.)"",
223         ""location"": {
224           ""lat"": 34.35067978344854,
225           ""lng"": 134.04693603515625
226         }
227       }
228     }
229   }
230 }";
231             var jsonBytes = Encoding.UTF8.GetBytes(json);
232             var location = FoursquareCheckin.ParseIntoLocation(jsonBytes);
233
234             Assert.NotNull(location);
235             Assert.Equal(34.35067978344854, location!.Latitude);
236             Assert.Equal(134.04693603515625, location.Longitude);
237         }
238
239         [Fact]
240         public void ParseInLocation_CultureTest()
241         {
242             var json = @"{
243   ""meta"": { ""code"": 200 },
244   ""response"": {
245     ""checkin"": {
246       ""id"": ""xxxxxxxxx"",
247       ""type"": ""checkin"",
248       ""venue"": {
249         ""id"": ""4b73dedcf964a5206bbe2de3"",
250         ""name"": ""高松駅 (Takamatsu Sta.)"",
251         ""location"": {
252           ""lat"": 34.35067978344854,
253           ""lng"": 134.04693603515625
254         }
255       }
256     }
257   }
258 }";
259             var origCulture = Thread.CurrentThread.CurrentCulture;
260             Thread.CurrentThread.CurrentCulture = new CultureInfo("ru-RU");
261
262             var jsonBytes = Encoding.UTF8.GetBytes(json);
263             var location = FoursquareCheckin.ParseIntoLocation(jsonBytes);
264
265             Thread.CurrentThread.CurrentCulture = origCulture;
266
267             Assert.NotNull(location);
268             Assert.Equal(34.35067978344854, location!.Latitude);
269             Assert.Equal(134.04693603515625, location.Longitude);
270         }
271
272         [Fact]
273         public void ParseInLocation_PlanetTest()
274         {
275             var json = @"{
276   ""meta"": { ""code"": 200 },
277   ""response"": {
278     ""checkin"": {
279       ""id"": ""xxxxxxxxx"",
280       ""type"": ""checkin"",
281       ""venue"": {
282         ""id"": ""5069d8bdc640385aa7711fe4"",
283         ""name"": ""Gale Crater"",
284         ""location"": {
285           ""planet"": ""mars"",
286           ""lat"": 34.201694,
287           ""lng"": -118.17166
288         }
289       }
290     }
291   }
292 }";
293             var jsonBytes = Encoding.UTF8.GetBytes(json);
294             var location = FoursquareCheckin.ParseIntoLocation(jsonBytes);
295
296             // 地球以外の位置にあるベニューに対しては null を返す
297             Assert.Null(location);
298         }
299
300         [Fact]
301         public void ParseInLocation_VenueNullTest()
302         {
303             var json = @"{
304   ""meta"": { ""code"": 200 },
305   ""response"": {
306     ""checkin"": {
307       ""id"": ""xxxxxxxxx"",
308       ""type"": ""checkin"",
309       ""venue"": null
310     }
311   }
312 }";
313             var jsonBytes = Encoding.UTF8.GetBytes(json);
314             var location = FoursquareCheckin.ParseIntoLocation(jsonBytes);
315
316             // ベニュー情報が得られなかった場合は null を返す
317             Assert.Null(location);
318         }
319     }
320 }