1package mastodon
2
3import (
4	"context"
5	"fmt"
6	"net/http"
7	"net/http/httptest"
8	"testing"
9)
10
11func TestGetFavourites(t *testing.T) {
12	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
13		fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
14		return
15	}))
16	defer ts.Close()
17
18	client := NewClient(&Config{
19		Server:       ts.URL,
20		ClientID:     "foo",
21		ClientSecret: "bar",
22		AccessToken:  "zoo",
23	})
24	favs, err := client.GetFavourites(context.Background(), nil)
25	if err != nil {
26		t.Fatalf("should not be fail: %v", err)
27	}
28	if len(favs) != 2 {
29		t.Fatalf("result should be two: %d", len(favs))
30	}
31	if favs[0].Content != "foo" {
32		t.Fatalf("want %q but %q", "foo", favs[0].Content)
33	}
34	if favs[1].Content != "bar" {
35		t.Fatalf("want %q but %q", "bar", favs[1].Content)
36	}
37}
38
39func TestGetStatus(t *testing.T) {
40	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
41		if r.URL.Path != "/api/v1/statuses/1234567" {
42			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
43			return
44		}
45		fmt.Fprintln(w, `{"content": "zzz", "emojis":[{"shortcode":"��", "url":"http://example.com", "static_url": "http://example.com/static"}]}`)
46		return
47	}))
48	defer ts.Close()
49
50	client := NewClient(&Config{
51		Server:       ts.URL,
52		ClientID:     "foo",
53		ClientSecret: "bar",
54		AccessToken:  "zoo",
55	})
56	_, err := client.GetStatus(context.Background(), "123")
57	if err == nil {
58		t.Fatalf("should be fail: %v", err)
59	}
60	status, err := client.GetStatus(context.Background(), "1234567")
61	if err != nil {
62		t.Fatalf("should not be fail: %v", err)
63	}
64	if status.Content != "zzz" {
65		t.Fatalf("want %q but %q", "zzz", status.Content)
66	}
67	if len(status.Emojis) != 1 {
68		t.Fatal("should have emojis")
69	}
70	if status.Emojis[0].ShortCode != "��" {
71		t.Fatalf("want %q but %q", "��", status.Emojis[0].ShortCode)
72	}
73	if status.Emojis[0].URL != "http://example.com" {
74		t.Fatalf("want %q but %q", "https://example.com", status.Emojis[0].URL)
75	}
76	if status.Emojis[0].StaticURL != "http://example.com/static" {
77		t.Fatalf("want %q but %q", "https://example.com/static", status.Emojis[0].StaticURL)
78	}
79}
80
81func TestGetStatusCard(t *testing.T) {
82	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
83		if r.URL.Path != "/api/v1/statuses/1234567/card" {
84			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
85			return
86		}
87		fmt.Fprintln(w, `{"title": "zzz"}`)
88		return
89	}))
90	defer ts.Close()
91
92	client := NewClient(&Config{
93		Server:       ts.URL,
94		ClientID:     "foo",
95		ClientSecret: "bar",
96		AccessToken:  "zoo",
97	})
98	_, err := client.GetStatusCard(context.Background(), "123")
99	if err == nil {
100		t.Fatalf("should be fail: %v", err)
101	}
102	card, err := client.GetStatusCard(context.Background(), "1234567")
103	if err != nil {
104		t.Fatalf("should not be fail: %v", err)
105	}
106	if card.Title != "zzz" {
107		t.Fatalf("want %q but %q", "zzz", card.Title)
108	}
109}
110
111func TestGetStatusContext(t *testing.T) {
112	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
113		if r.URL.Path != "/api/v1/statuses/1234567/context" {
114			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
115			return
116		}
117		fmt.Fprintln(w, `{"ancestors": [{"content": "zzz"},{"content": "bbb"}]}`)
118		return
119	}))
120	defer ts.Close()
121
122	client := NewClient(&Config{
123		Server:       ts.URL,
124		ClientID:     "foo",
125		ClientSecret: "bar",
126		AccessToken:  "zoo",
127	})
128	_, err := client.GetStatusContext(context.Background(), "123")
129	if err == nil {
130		t.Fatalf("should be fail: %v", err)
131	}
132	context, err := client.GetStatusContext(context.Background(), "1234567")
133	if err != nil {
134		t.Fatalf("should not be fail: %v", err)
135	}
136	if len(context.Ancestors) != 2 {
137		t.Fatalf("Ancestors should have 2 entries but %q", len(context.Ancestors))
138	}
139	if context.Ancestors[0].Content != "zzz" {
140		t.Fatalf("want %q but %q", "zzz", context.Ancestors[0].Content)
141	}
142	if context.Ancestors[1].Content != "bbb" {
143		t.Fatalf("want %q but %q", "bbb", context.Ancestors[1].Content)
144	}
145	if len(context.Descendants) > 0 {
146		t.Fatalf("Descendants should not be included")
147	}
148}
149
150func TestGetRebloggedBy(t *testing.T) {
151	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
152		if r.URL.Path != "/api/v1/statuses/1234567/reblogged_by" {
153			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
154			return
155		}
156		fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
157		return
158	}))
159	defer ts.Close()
160
161	client := NewClient(&Config{
162		Server:       ts.URL,
163		ClientID:     "foo",
164		ClientSecret: "bar",
165		AccessToken:  "zoo",
166	})
167	_, err := client.GetRebloggedBy(context.Background(), "123", nil)
168	if err == nil {
169		t.Fatalf("should be fail: %v", err)
170	}
171	rbs, err := client.GetRebloggedBy(context.Background(), "1234567", nil)
172	if err != nil {
173		t.Fatalf("should not be fail: %v", err)
174	}
175	if len(rbs) != 2 {
176		t.Fatalf("result should be two: %d", len(rbs))
177	}
178	if rbs[0].Username != "foo" {
179		t.Fatalf("want %q but %q", "foo", rbs[0].Username)
180	}
181	if rbs[1].Username != "bar" {
182		t.Fatalf("want %q but %q", "bar", rbs[1].Username)
183	}
184}
185
186func TestGetFavouritedBy(t *testing.T) {
187	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
188		if r.URL.Path != "/api/v1/statuses/1234567/favourited_by" {
189			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
190			return
191		}
192		fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
193		return
194	}))
195	defer ts.Close()
196
197	client := NewClient(&Config{
198		Server:       ts.URL,
199		ClientID:     "foo",
200		ClientSecret: "bar",
201		AccessToken:  "zoo",
202	})
203	_, err := client.GetFavouritedBy(context.Background(), "123", nil)
204	if err == nil {
205		t.Fatalf("should be fail: %v", err)
206	}
207	fbs, err := client.GetFavouritedBy(context.Background(), "1234567", nil)
208	if err != nil {
209		t.Fatalf("should not be fail: %v", err)
210	}
211	if len(fbs) != 2 {
212		t.Fatalf("result should be two: %d", len(fbs))
213	}
214	if fbs[0].Username != "foo" {
215		t.Fatalf("want %q but %q", "foo", fbs[0].Username)
216	}
217	if fbs[1].Username != "bar" {
218		t.Fatalf("want %q but %q", "bar", fbs[1].Username)
219	}
220}
221
222func TestReblog(t *testing.T) {
223	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
224		if r.URL.Path != "/api/v1/statuses/1234567/reblog" {
225			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
226			return
227		}
228		fmt.Fprintln(w, `{"content": "zzz"}`)
229		return
230	}))
231	defer ts.Close()
232
233	client := NewClient(&Config{
234		Server:       ts.URL,
235		ClientID:     "foo",
236		ClientSecret: "bar",
237		AccessToken:  "zoo",
238	})
239	_, err := client.Reblog(context.Background(), "123")
240	if err == nil {
241		t.Fatalf("should be fail: %v", err)
242	}
243	status, err := client.Reblog(context.Background(), "1234567")
244	if err != nil {
245		t.Fatalf("should not be fail: %v", err)
246	}
247	if status.Content != "zzz" {
248		t.Fatalf("want %q but %q", "zzz", status.Content)
249	}
250}
251
252func TestUnreblog(t *testing.T) {
253	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
254		if r.URL.Path != "/api/v1/statuses/1234567/unreblog" {
255			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
256			return
257		}
258		fmt.Fprintln(w, `{"content": "zzz"}`)
259		return
260	}))
261	defer ts.Close()
262
263	client := NewClient(&Config{
264		Server:       ts.URL,
265		ClientID:     "foo",
266		ClientSecret: "bar",
267		AccessToken:  "zoo",
268	})
269	_, err := client.Unreblog(context.Background(), "123")
270	if err == nil {
271		t.Fatalf("should be fail: %v", err)
272	}
273	status, err := client.Unreblog(context.Background(), "1234567")
274	if err != nil {
275		t.Fatalf("should not be fail: %v", err)
276	}
277	if status.Content != "zzz" {
278		t.Fatalf("want %q but %q", "zzz", status.Content)
279	}
280}
281
282func TestFavourite(t *testing.T) {
283	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
284		if r.URL.Path != "/api/v1/statuses/1234567/favourite" {
285			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
286			return
287		}
288		fmt.Fprintln(w, `{"content": "zzz"}`)
289		return
290	}))
291	defer ts.Close()
292
293	client := NewClient(&Config{
294		Server:       ts.URL,
295		ClientID:     "foo",
296		ClientSecret: "bar",
297		AccessToken:  "zoo",
298	})
299	_, err := client.Favourite(context.Background(), "123")
300	if err == nil {
301		t.Fatalf("should be fail: %v", err)
302	}
303	status, err := client.Favourite(context.Background(), "1234567")
304	if err != nil {
305		t.Fatalf("should not be fail: %v", err)
306	}
307	if status.Content != "zzz" {
308		t.Fatalf("want %q but %q", "zzz", status.Content)
309	}
310}
311
312func TestUnfavourite(t *testing.T) {
313	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
314		if r.URL.Path != "/api/v1/statuses/1234567/unfavourite" {
315			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
316			return
317		}
318		fmt.Fprintln(w, `{"content": "zzz"}`)
319		return
320	}))
321	defer ts.Close()
322
323	client := NewClient(&Config{
324		Server:       ts.URL,
325		ClientID:     "foo",
326		ClientSecret: "bar",
327		AccessToken:  "zoo",
328	})
329	_, err := client.Unfavourite(context.Background(), "123")
330	if err == nil {
331		t.Fatalf("should be fail: %v", err)
332	}
333	status, err := client.Unfavourite(context.Background(), "1234567")
334	if err != nil {
335		t.Fatalf("should not be fail: %v", err)
336	}
337	if status.Content != "zzz" {
338		t.Fatalf("want %q but %q", "zzz", status.Content)
339	}
340}
341
342func TestGetTimelinePublic(t *testing.T) {
343	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
344		if r.URL.Query().Get("local") == "" {
345			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
346			return
347		}
348		fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
349	}))
350	defer ts.Close()
351
352	client := NewClient(&Config{Server: ts.URL})
353	_, err := client.GetTimelinePublic(context.Background(), false, nil)
354	if err == nil {
355		t.Fatalf("should be fail: %v", err)
356	}
357	tl, err := client.GetTimelinePublic(context.Background(), true, nil)
358	if err != nil {
359		t.Fatalf("should not be fail: %v", err)
360	}
361	if len(tl) != 2 {
362		t.Fatalf("result should be two: %d", len(tl))
363	}
364	if tl[0].Content != "foo" {
365		t.Fatalf("want %q but %q", "foo", tl[0].Content)
366	}
367	if tl[1].Content != "bar" {
368		t.Fatalf("want %q but %q", "bar", tl[1].Content)
369	}
370}
371
372func TestGetTimelineHashtag(t *testing.T) {
373	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
374		if r.URL.Path != "/api/v1/timelines/tag/zzz" {
375			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
376			return
377		}
378		fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
379		return
380	}))
381	defer ts.Close()
382
383	client := NewClient(&Config{
384		Server:       ts.URL,
385		ClientID:     "foo",
386		ClientSecret: "bar",
387		AccessToken:  "zoo",
388	})
389	_, err := client.GetTimelineHashtag(context.Background(), "notfound", false, nil)
390	if err == nil {
391		t.Fatalf("should be fail: %v", err)
392	}
393	tags, err := client.GetTimelineHashtag(context.Background(), "zzz", true, nil)
394	if err != nil {
395		t.Fatalf("should not be fail: %v", err)
396	}
397	if len(tags) != 2 {
398		t.Fatalf("should have %q entries but %q", "2", len(tags))
399	}
400	if tags[0].Content != "zzz" {
401		t.Fatalf("want %q but %q", "zzz", tags[0].Content)
402	}
403	if tags[1].Content != "yyy" {
404		t.Fatalf("want %q but %q", "zzz", tags[1].Content)
405	}
406}
407
408func TestGetTimelineMedia(t *testing.T) {
409	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
410		if r.URL.Query().Get("local") == "" {
411			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
412			return
413		}
414		fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
415		return
416	}))
417	defer ts.Close()
418
419	client := NewClient(&Config{
420		Server:       ts.URL,
421		ClientID:     "foo",
422		ClientSecret: "bar",
423		AccessToken:  "zoo",
424	})
425	_, err := client.GetTimelineMedia(context.Background(), false, nil)
426	if err == nil {
427		t.Fatalf("should be fail: %v", err)
428	}
429	tags, err := client.GetTimelineMedia(context.Background(), true, nil)
430	if err != nil {
431		t.Fatalf("should not be fail: %v", err)
432	}
433	if len(tags) != 2 {
434		t.Fatalf("should have %q entries but %q", "2", len(tags))
435	}
436	if tags[0].Content != "zzz" {
437		t.Fatalf("want %q but %q", "zzz", tags[0].Content)
438	}
439	if tags[1].Content != "yyy" {
440		t.Fatalf("want %q but %q", "zzz", tags[1].Content)
441	}
442}
443
444func TestDeleteStatus(t *testing.T) {
445	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
446		if r.URL.Path != "/api/v1/statuses/1234567" {
447			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
448			return
449		}
450		if r.Method != "DELETE" {
451			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
452			return
453		}
454		return
455	}))
456	defer ts.Close()
457
458	client := NewClient(&Config{
459		Server:       ts.URL,
460		ClientID:     "foo",
461		ClientSecret: "bar",
462		AccessToken:  "zoo",
463	})
464	err := client.DeleteStatus(context.Background(), "123")
465	if err == nil {
466		t.Fatalf("should be fail: %v", err)
467	}
468	err = client.DeleteStatus(context.Background(), "1234567")
469	if err != nil {
470		t.Fatalf("should not be fail: %v", err)
471	}
472}
473
474func TestSearch(t *testing.T) {
475	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
476		if r.URL.Path != "/api/v1/search" {
477			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
478			return
479		}
480		if r.RequestURI != "/api/v1/search?q=q&resolve=false" {
481			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusBadRequest)
482			return
483		}
484
485		fmt.Fprintln(w, `
486			{"accounts":[{"username": "zzz"},{"username": "yyy"}],
487			"statuses":[{"content": "aaa"}],
488			"hashtags":["tag","tag2","tag3"]
489		}`)
490		return
491	}))
492	defer ts.Close()
493
494	client := NewClient(&Config{
495		Server:       ts.URL,
496		ClientID:     "foo",
497		ClientSecret: "bar",
498		AccessToken:  "zoo",
499	})
500	ret, err := client.Search(context.Background(), "q", false)
501	if err != nil {
502		t.Fatalf("should not be fail: %v", err)
503	}
504	if len(ret.Accounts) != 2 {
505		t.Fatalf("Accounts have %q entries, but %q", "2", len(ret.Accounts))
506	}
507	if ret.Accounts[0].Username != "zzz" {
508		t.Fatalf("Accounts Username should %q , but %q", "zzz", ret.Accounts[0].Username)
509	}
510	if len(ret.Statuses) != 1 {
511		t.Fatalf("Statuses have %q entries, but %q", "1", len(ret.Statuses))
512	}
513	if ret.Statuses[0].Content != "aaa" {
514		t.Fatalf("Statuses Content should %q , but %q", "aaa", ret.Statuses[0].Content)
515	}
516	if len(ret.Hashtags) != 3 {
517		t.Fatalf("Hashtags have %q entries, but %q", "3", len(ret.Hashtags))
518	}
519	if ret.Hashtags[2] != "tag3" {
520		t.Fatalf("Hashtags[2] should %q , but %q", "tag3", ret.Hashtags[2])
521	}
522}
523
524func TestUploadMedia(t *testing.T) {
525	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
526		if r.URL.Path != "/api/v1/media" {
527			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
528			return
529		}
530		if r.Method != "POST" {
531			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
532			return
533		}
534		fmt.Fprintln(w, `{"id": 123}`)
535		return
536	}))
537	defer ts.Close()
538
539	client := NewClient(&Config{
540		Server:       ts.URL,
541		ClientID:     "foo",
542		ClientSecret: "bar",
543		AccessToken:  "zoo",
544	})
545	attachment, err := client.UploadMedia(context.Background(), "testdata/logo.png")
546	if err != nil {
547		t.Fatalf("should not be fail: %v", err)
548	}
549	if attachment.ID != "123" {
550		t.Fatalf("want %q but %q", "123", attachment.ID)
551	}
552}
553