add new commit

This commit is contained in:
Rasmus Lindroth 2022-05-15 20:44:09 +02:00
parent 7544964508
commit ea59675755
12 changed files with 123 additions and 38 deletions

View file

@ -98,6 +98,11 @@ func main() {
* [x] DELETE /api/v1/conversations/:id
* [x] POST /api/v1/conversations/:id/read
* [x] GET /api/v1/favourites
* [x] GET /api/v1/filters
* [x] POST /api/v1/filters
* [x] GET /api/v1/filters/:id
* [x] PUT /api/v1/filters/:id
* [x] DELETE /api/v1/filters/:id
* [x] GET /api/v1/follow_requests
* [x] POST /api/v1/follow_requests/:id/authorize
* [x] POST /api/v1/follow_requests/:id/reject
@ -153,7 +158,7 @@ func main() {
## Installation
```
$ go get github.com/mattn/go-mastodon
$ go get github.com/RasmusLindroth/go-mastodon
```
## License

View file

@ -118,6 +118,7 @@ func TestGetAccountStatuses(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
return
}))
defer ts.Close()
@ -150,6 +151,7 @@ func TestGetAccountFollowers(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()
@ -185,6 +187,7 @@ func TestGetAccountFollowing(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()
@ -222,6 +225,7 @@ func TestGetBlocks(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()
@ -257,6 +261,7 @@ func TestAccountFollow(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id":1234567,"following":true}`)
return
}))
defer ts.Close()
@ -266,11 +271,11 @@ func TestAccountFollow(t *testing.T) {
ClientSecret: "bar",
AccessToken: "zoo",
})
_, err := client.AccountFollow(context.Background(), "123")
rel, err := client.AccountFollow(context.Background(), "123")
if err == nil {
t.Fatalf("should be fail: %v", err)
}
rel, err := client.AccountFollow(context.Background(), "1234567")
rel, err = client.AccountFollow(context.Background(), "1234567")
if err != nil {
t.Fatalf("should not be fail: %v", err)
}
@ -289,6 +294,7 @@ func TestAccountUnfollow(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id":1234567,"following":false}`)
return
}))
defer ts.Close()
@ -298,11 +304,11 @@ func TestAccountUnfollow(t *testing.T) {
ClientSecret: "bar",
AccessToken: "zoo",
})
_, err := client.AccountUnfollow(context.Background(), "123")
rel, err := client.AccountUnfollow(context.Background(), "123")
if err == nil {
t.Fatalf("should be fail: %v", err)
}
rel, err := client.AccountUnfollow(context.Background(), "1234567")
rel, err = client.AccountUnfollow(context.Background(), "1234567")
if err != nil {
t.Fatalf("should not be fail: %v", err)
}
@ -321,6 +327,7 @@ func TestAccountBlock(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id":1234567,"blocking":true}`)
return
}))
defer ts.Close()
@ -353,6 +360,7 @@ func TestAccountUnblock(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id":1234567,"blocking":false}`)
return
}))
defer ts.Close()
@ -385,6 +393,7 @@ func TestAccountMute(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id":1234567,"muting":true}`)
return
}))
defer ts.Close()
@ -417,6 +426,7 @@ func TestAccountUnmute(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id":1234567,"muting":false}`)
return
}))
defer ts.Close()
@ -482,6 +492,7 @@ func TestAccountsSearch(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foobar"}, {"username": "barfoo"}]`)
return
}))
defer ts.Close()
@ -517,6 +528,7 @@ func TestFollowRemoteUser(t *testing.T) {
return
}
fmt.Fprintln(w, `{"username": "zzz"}`)
return
}))
defer ts.Close()
@ -548,6 +560,7 @@ func TestGetFollowRequests(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()
@ -633,6 +646,7 @@ func TestGetMutes(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()

View file

@ -27,6 +27,7 @@ func TestRegisterApp(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id": 123, "client_id": "foo", "client_secret": "bar"}`)
return
}))
defer ts.Close()
@ -78,6 +79,7 @@ func TestRegisterAppWithCancel(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(3 * time.Second)
fmt.Fprintln(w, `{"client_id": "foo", "client_secret": "bar"}`)
return
}))
defer ts.Close()

View file

@ -14,7 +14,7 @@ func ExampleRegisterApp() {
Server: "https://mstdn.jp",
ClientName: "client-name",
Scopes: "read write follow",
Website: "https://github.com/mattn/go-mastodon",
Website: "https://github.com/RasmusLindroth/go-mastodon",
})
if err != nil {
log.Fatal(err)

View file

@ -322,10 +322,6 @@ func TestDeleteFilter(t *testing.T) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
if r.Method != "DELETE" {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
return
}
}))
defer ts.Close()

View file

@ -15,6 +15,7 @@ func TestGetLists(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"id": "1", "title": "foo"}, {"id": "2", "title": "bar"}]`)
return
}))
defer ts.Close()
@ -46,6 +47,7 @@ func TestGetAccountLists(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"id": "1", "title": "foo"}, {"id": "2", "title": "bar"}]`)
return
}))
defer ts.Close()
@ -81,6 +83,7 @@ func TestGetListAccounts(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()
@ -116,6 +119,7 @@ func TestGetList(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id": "1", "title": "foo"}`)
return
}))
defer ts.Close()
@ -125,11 +129,11 @@ func TestGetList(t *testing.T) {
ClientSecret: "bar",
AccessToken: "zoo",
})
_, err := client.GetList(context.Background(), "2")
list, err := client.GetList(context.Background(), "2")
if err == nil {
t.Fatalf("should be fail: %v", err)
}
list, err := client.GetList(context.Background(), "1")
list, err = client.GetList(context.Background(), "1")
if err != nil {
t.Fatalf("should not be fail: %v", err)
}
@ -145,6 +149,7 @@ func TestCreateList(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id": "1", "title": "foo"}`)
return
}))
defer ts.Close()
@ -154,11 +159,11 @@ func TestCreateList(t *testing.T) {
ClientSecret: "bar",
AccessToken: "zoo",
})
_, err := client.CreateList(context.Background(), "")
list, err := client.CreateList(context.Background(), "")
if err == nil {
t.Fatalf("should be fail: %v", err)
}
list, err := client.CreateList(context.Background(), "foo")
list, err = client.CreateList(context.Background(), "foo")
if err != nil {
t.Fatalf("should not be fail: %v", err)
}
@ -178,6 +183,7 @@ func TestRenameList(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id": "1", "title": "bar"}`)
return
}))
defer ts.Close()
@ -187,11 +193,11 @@ func TestRenameList(t *testing.T) {
ClientSecret: "bar",
AccessToken: "zoo",
})
_, err := client.RenameList(context.Background(), "2", "bar")
list, err := client.RenameList(context.Background(), "2", "bar")
if err == nil {
t.Fatalf("should be fail: %v", err)
}
list, err := client.RenameList(context.Background(), "1", "bar")
list, err = client.RenameList(context.Background(), "1", "bar")
if err != nil {
t.Fatalf("should not be fail: %v", err)
}
@ -210,6 +216,7 @@ func TestDeleteList(t *testing.T) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
return
}
return
}))
defer ts.Close()
@ -239,6 +246,7 @@ func TestAddToList(t *testing.T) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
return
}))
defer ts.Close()
@ -264,6 +272,7 @@ func TestRemoveFromList(t *testing.T) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
return
}
return
}))
defer ts.Close()

View file

@ -96,6 +96,7 @@ func TestAuthenticate(t *testing.T) {
return
}
fmt.Fprintln(w, `{"access_token": "zoo"}`)
return
}))
defer ts.Close()
@ -123,6 +124,7 @@ func TestAuthenticate(t *testing.T) {
func TestAuthenticateWithCancel(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(3 * time.Second)
return
}))
defer ts.Close()
@ -149,6 +151,7 @@ func TestPostStatus(t *testing.T) {
return
}
fmt.Fprintln(w, `{"access_token": "zoo"}`)
return
}))
defer ts.Close()
@ -181,6 +184,7 @@ func TestPostStatus(t *testing.T) {
func TestPostStatusWithCancel(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(3 * time.Second)
return
}))
defer ts.Close()
@ -315,6 +319,7 @@ func TestPostStatusParams(t *testing.T) {
func TestGetTimelineHome(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
return
}))
defer ts.Close()
@ -354,6 +359,7 @@ func TestGetTimelineHome(t *testing.T) {
func TestGetTimelineHomeWithCancel(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(3 * time.Second)
return
}))
defer ts.Close()

View file

@ -28,6 +28,7 @@ func TestGetNotifications(t *testing.T) {
return
}
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}))
defer ts.Close()
@ -75,6 +76,7 @@ func TestPushSubscription(t *testing.T) {
return
}
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}))
defer ts.Close()

View file

@ -15,6 +15,7 @@ func TestGetReports(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"id": 122, "action_taken": false}, {"id": 123, "action_taken": true}]`)
return
}))
defer ts.Close()
@ -54,6 +55,7 @@ func TestReport(t *testing.T) {
} else {
fmt.Fprintln(w, `{"id": 1234, "action_taken": true}`)
}
return
}))
defer ts.Close()
@ -63,11 +65,11 @@ func TestReport(t *testing.T) {
ClientSecret: "bar",
AccessToken: "zoo",
})
_, err := client.Report(context.Background(), "121", nil, "")
rp, err := client.Report(context.Background(), "121", nil, "")
if err == nil {
t.Fatalf("should be fail: %v", err)
}
rp, err := client.Report(context.Background(), "122", nil, "")
rp, err = client.Report(context.Background(), "122", nil, "")
if err != nil {
t.Fatalf("should not be fail: %v", err)
}

View file

@ -12,6 +12,7 @@ import (
func TestGetFavourites(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
return
}))
defer ts.Close()
@ -39,6 +40,7 @@ func TestGetFavourites(t *testing.T) {
func TestGetBookmarks(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
return
}))
defer ts.Close()
@ -70,6 +72,7 @@ func TestGetStatus(t *testing.T) {
return
}
fmt.Fprintln(w, `{"content": "zzz", "emojis":[{"shortcode":"💩", "url":"http://example.com", "static_url": "http://example.com/static"}]}`)
return
}))
defer ts.Close()
@ -111,6 +114,7 @@ func TestGetStatusCard(t *testing.T) {
return
}
fmt.Fprintln(w, `{"title": "zzz"}`)
return
}))
defer ts.Close()
@ -140,6 +144,7 @@ func TestGetStatusContext(t *testing.T) {
return
}
fmt.Fprintln(w, `{"ancestors": [{"content": "zzz"},{"content": "bbb"}]}`)
return
}))
defer ts.Close()
@ -178,6 +183,7 @@ func TestGetRebloggedBy(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()
@ -213,6 +219,7 @@ func TestGetFavouritedBy(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
return
}))
defer ts.Close()
@ -248,6 +255,7 @@ func TestReblog(t *testing.T) {
return
}
fmt.Fprintln(w, `{"content": "zzz"}`)
return
}))
defer ts.Close()
@ -277,6 +285,7 @@ func TestUnreblog(t *testing.T) {
return
}
fmt.Fprintln(w, `{"content": "zzz"}`)
return
}))
defer ts.Close()
@ -306,6 +315,7 @@ func TestFavourite(t *testing.T) {
return
}
fmt.Fprintln(w, `{"content": "zzz"}`)
return
}))
defer ts.Close()
@ -335,6 +345,7 @@ func TestUnfavourite(t *testing.T) {
return
}
fmt.Fprintln(w, `{"content": "zzz"}`)
return
}))
defer ts.Close()
@ -364,6 +375,7 @@ func TestBookmark(t *testing.T) {
return
}
fmt.Fprintln(w, `{"content": "zzz"}`)
return
}))
defer ts.Close()
@ -393,6 +405,7 @@ func TestUnbookmark(t *testing.T) {
return
}
fmt.Fprintln(w, `{"content": "zzz"}`)
return
}))
defer ts.Close()
@ -474,6 +487,7 @@ func TestGetTimelineHashtag(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
return
}))
defer ts.Close()
@ -509,6 +523,7 @@ func TestGetTimelineList(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
return
}))
defer ts.Close()
@ -544,6 +559,7 @@ func TestGetTimelineMedia(t *testing.T) {
return
}
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
return
}))
defer ts.Close()
@ -582,6 +598,7 @@ func TestDeleteStatus(t *testing.T) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
return
}
return
}))
defer ts.Close()
@ -617,6 +634,7 @@ func TestSearch(t *testing.T) {
"statuses":[{"content": "aaa"}],
"hashtags":[{"name": "tag"},{"name": "tag2"},{"name": "tag3"}]
}`)
return
}))
defer ts.Close()
@ -661,6 +679,7 @@ func TestUploadMedia(t *testing.T) {
return
}
fmt.Fprintln(w, `{"id": 123}`)
return
}))
defer ts.Close()
@ -697,6 +716,7 @@ func TestGetConversations(t *testing.T) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
fmt.Fprintln(w, `[{"id": "4", "unread":false, "last_status" : {"content": "zzz"}}, {"id": "3", "unread":true, "last_status" : {"content": "bar"}}]`)
return
}))
defer ts.Close()
@ -734,6 +754,7 @@ func TestDeleteConversation(t *testing.T) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
return
}
return
}))
defer ts.Close()
@ -759,6 +780,7 @@ func TestMarkConversationsAsRead(t *testing.T) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
return
}))
defer ts.Close()

View file

@ -2,8 +2,10 @@ package mastodon
import (
"bufio"
"bytes"
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/url"
@ -43,10 +45,27 @@ type Event interface {
func handleReader(q chan Event, r io.Reader) error {
var name string
s := bufio.NewScanner(r)
for s.Scan() {
line := s.Text()
token := strings.SplitN(line, ":", 2)
var lineBuf bytes.Buffer
br := bufio.NewReader(r)
for {
line, isPrefix, err := br.ReadLine()
if err != nil {
if errors.Is(err, io.EOF) {
return nil
}
return err
}
if isPrefix {
lineBuf.Write(line)
continue
}
if lineBuf.Len() > 0 {
lineBuf.Write(line)
line = lineBuf.Bytes()
lineBuf.Reset()
}
token := strings.SplitN(string(line), ":", 2)
if len(token) != 2 {
continue
}
@ -76,7 +95,6 @@ func handleReader(q chan Event, r io.Reader) error {
}
}
}
return s.Err()
}
func (c *Client) streaming(ctx context.Context, p string, params url.Values) (chan Event, error) {

View file

@ -1,6 +1,7 @@
package mastodon
import (
"bufio"
"context"
"fmt"
"net/http"
@ -11,31 +12,40 @@ import (
)
func TestHandleReader(t *testing.T) {
large := "large"
largeContent := strings.Repeat(large, 2*(bufio.MaxScanTokenSize/len(large)))
q := make(chan Event)
r := strings.NewReader(`
r := strings.NewReader(fmt.Sprintf(`
event: update
data: {content: error}
event: update
data: {"content": "foo"}
event: update
data: {"content": "%s"}
event: notification
data: {"type": "mention"}
event: delete
data: 1234567
:thump
`)
errs := make(chan error, 1)
`, largeContent))
go func() {
defer close(q)
err := handleReader(q, r)
errs <- err
if err != nil {
t.Fatalf("should not be fail: %v", err)
}
}()
var passUpdate, passNotification, passDelete, passError bool
var passUpdate, passUpdateLarge, passNotification, passDelete, passError bool
for e := range q {
switch event := e.(type) {
case *UpdateEvent:
passUpdate = true
if event.Status.Content != "foo" {
t.Fatalf("want %q but %q", "foo", event.Status.Content)
if event.Status.Content == "foo" {
passUpdate = true
} else if event.Status.Content == largeContent {
passUpdateLarge = true
} else {
t.Fatalf("bad update content: %q", event.Status.Content)
}
case *NotificationEvent:
passNotification = true
@ -54,14 +64,10 @@ data: 1234567
}
}
}
if !passUpdate || !passNotification || !passDelete || !passError {
if !passUpdate || !passUpdateLarge || !passNotification || !passDelete || !passError {
t.Fatalf("have not passed through somewhere: "+
"update %t, notification %t, delete %t, error %t",
passUpdate, passNotification, passDelete, passError)
}
err := <-errs
if err != nil {
t.Fatalf("should not be fail: %v", err)
"update: %t, update (large): %t, notification: %t, delete: %t, error: %t",
passUpdate, passUpdateLarge, passNotification, passDelete, passError)
}
}
@ -145,6 +151,9 @@ func TestDoStreaming(t *testing.T) {
go func() {
defer close(q)
c.doStreaming(req, q)
if err != nil {
t.Fatalf("should not be fail: %v", err)
}
}()
var passError bool
for e := range q {