aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lisp/mastodon-async.el7
-rw-r--r--lisp/mastodon-auth.el2
-rw-r--r--lisp/mastodon-client.el2
-rw-r--r--lisp/mastodon-discover.el2
-rw-r--r--lisp/mastodon-http.el2
-rw-r--r--lisp/mastodon-inspect.el2
-rw-r--r--lisp/mastodon-media.el2
-rw-r--r--lisp/mastodon-notifications.el13
-rw-r--r--lisp/mastodon-profile.el33
-rw-r--r--lisp/mastodon-search.el49
-rw-r--r--lisp/mastodon-tl.el101
-rw-r--r--lisp/mastodon-toot.el3
-rw-r--r--lisp/mastodon.el3
-rw-r--r--test/mastodon-profile-tests.el288
-rw-r--r--test/mastodon-search-tests.el5
-rw-r--r--test/mastodon-tl-tests.el2
16 files changed, 426 insertions, 90 deletions
diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el
index 6ff09e3..86547a1 100644
--- a/lisp/mastodon-async.el
+++ b/lisp/mastodon-async.el
@@ -1,12 +1,11 @@
;;; mastodon-async.el --- Client for Mastodon -*- lexical-binding: t -*-
-;; Copyright (C) 2017 Johnson Denen
-;; Author: Johnson Denen <johnson.denen@gmail.com>
-;; Alex J. Griffith <griffitaj@gmail.com>
+;; Copyright (C) 2017 Alex J. Griffith
+;; Author: Alex J. Griffith <griffitaj@gmail.com>
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el
index a3d51fa..1fb1604 100644
--- a/lisp/mastodon-auth.el
+++ b/lisp/mastodon-auth.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el
index b27d434..42e8b1f 100644
--- a/lisp/mastodon-client.el
+++ b/lisp/mastodon-client.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el
index 10abc59..7046070 100644
--- a/lisp/mastodon-discover.el
+++ b/lisp/mastodon-discover.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el
index f988e39..e288c18 100644
--- a/lisp/mastodon-http.el
+++ b/lisp/mastodon-http.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1") (request "0.3.0"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el
index b0270ee..15ee7ce 100644
--- a/lisp/mastodon-inspect.el
+++ b/lisp/mastodon-inspect.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el
index acce473..4e4a15d 100644
--- a/lisp/mastodon-media.el
+++ b/lisp/mastodon-media.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el
index 1361099..5e3305a 100644
--- a/lisp/mastodon-notifications.el
+++ b/lisp/mastodon-notifications.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
@@ -47,6 +47,8 @@
(autoload 'mastodon-tl--property "mastodon-tl.el")
(autoload 'mastodon-tl--spoiler "mastodon-tl.el")
(autoload 'mastodon-tl--toot-id "mastodon-tl.el")
+(autoload 'mastodon-http--get-params-async-json "mastodon-http.el")
+(defvar mastodon-tl--buffer-spec)
(defvar mastodon-tl--display-media-p)
(defvar mastodon-tl--buffer-spec)
@@ -221,7 +223,8 @@ takes a single function. By default it is
`mastodon-tl--byline-boosted'.
ID is the notification's own id, which is attached as a property."
- (mastodon-tl--insert-status toot body author-byline action-byline id))
+ (when toot ; handle rare blank notif server bug
+ (mastodon-tl--insert-status toot body author-byline action-byline id)))
(defun mastodon-notifications--by-type (note)
"Filters NOTE for those listed in `mastodon-notifications--types-alist'."
@@ -235,8 +238,10 @@ ID is the notification's own id, which is attached as a property."
(defun mastodon-notifications--timeline (json)
"Format JSON in Emacs buffer."
- (mapc #'mastodon-notifications--by-type json)
- (goto-char (point-min)))
+ (if (equal json '[])
+ (message "Looks like you have no notifications for the moment.")
+ (mapc #'mastodon-notifications--by-type json)
+ (goto-char (point-min))))
(defun mastodon-notifications--get ()
"Display NOTIFICATIONS in buffer."
diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el
index 21b40b3..5811a4a 100644
--- a/lisp/mastodon-profile.el
+++ b/lisp/mastodon-profile.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1") (seq "1.0"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
@@ -146,7 +146,6 @@ extra keybindings."
(defun mastodon-profile--view-follow-requests ()
"Open a new buffer displaying the user's follow requests."
(interactive)
- (mastodon-profile-mode)
(mastodon-tl--init "follow-requests"
"follow_requests"
'mastodon-profile--add-author-bylines))
@@ -386,20 +385,22 @@ FIELD is used to identify regions under 'account"
(defun mastodon-profile--add-author-bylines (tootv)
"Convert TOOTV into a author-bylines and insert."
(let ((inhibit-read-only t))
- (mapc (lambda (toot)
- (let ((start-pos (point)))
- (insert "\n"
- (propertize
- (mastodon-tl--byline-author `((account . ,toot)))
- 'byline 't
- 'toot-id (alist-get 'id toot)
- 'base-toot-id (mastodon-tl--toot-id toot)
- 'toot-json toot))
- (mastodon-media--inline-images start-pos (point))
- (insert "\n"
- (mastodon-tl--render-text (alist-get 'note toot) nil)
- "\n")))
- tootv)))
+ (if (equal tootv '[])
+ (message "Looks like you have no follow requests for the moment.")
+ (mapc (lambda (toot)
+ (let ((start-pos (point)))
+ (insert "\n"
+ (propertize
+ (mastodon-tl--byline-author `((account . ,toot)))
+ 'byline 't
+ 'toot-id (alist-get 'id toot)
+ 'base-toot-id (mastodon-tl--toot-id toot)
+ 'toot-json toot))
+ (mastodon-media--inline-images start-pos (point))
+ (insert "\n"
+ (mastodon-tl--render-text (alist-get 'note toot) nil)
+ "\n")))
+ tootv))))
(defun mastodon-profile--search-account-by-handle (handle)
"Return an account based on a user's HANDLE.
diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el
index 78c2ab4..8c654cc 100644
--- a/lisp/mastodon-search.el
+++ b/lisp/mastodon-search.el
@@ -1,12 +1,11 @@
;;; mastodon-search.el --- Search functions for mastodon.el -*- lexical-binding: t -*-
-;; Copyright (C) 2017-2019 Johnson Denen
-;; Author: Johnson Denen <johnson.denen@gmail.com>
-;; Marty Hiatt <martianhiatus@riseup.net>
+;; Copyright (C) 2017-2019 Marty Hiatt
+;; Author: Marty Hiatt <martianhiatus@riseup.net>
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
@@ -58,7 +57,7 @@
"Prompt for a search QUERY and return accounts synchronously.
Returns a nested list containing user handle, display name, and URL."
(interactive "sSearch mastodon for: ")
- (let* ((url (format "%s/api/v1/accounts/search" mastodon-instance-url))
+ (let* ((url (mastodon-http--api "accounts/search"))
;; (buffer (format "*mastodon-search-%s*" query))
(response (if (equal mastodon-toot--enable-completion-for-mentions "following")
(mastodon-http--get-search-json url query "following=true")
@@ -98,19 +97,7 @@ Returns a nested list containing user handle, display name, and URL."
" USERS\n"
" ------------\n\n")
'success))
- (mapc (lambda (el)
- (insert (propertize (car el) 'face 'mastodon-display-name-face)
- " : \n : "
- (propertize (concat "@" (car (cdr el)))
- 'face 'mastodon-handle-face
- 'mouse-face 'highlight
- 'mastodon-tab-stop 'user-handle
- 'keymap mastodon-tl--link-keymap
- 'mastodon-handle (concat "@" (car (cdr el)))
- 'help-echo (concat "Browse user profile of @" (car (cdr el))))
- " : \n"
- "\n"))
- user-ids)
+ (mastodon-search--insert-users-propertized user-ids :note)
;; hashtag results:
(insert (mastodon-tl--set-face
(concat "\n ------------\n"
@@ -136,11 +123,33 @@ Returns a nested list containing user handle, display name, and URL."
(mapc 'mastodon-tl--toot toots-list-json)
(goto-char (point-min))))))
+(defun mastodon-search--insert-users-propertized (users &optional note)
+ "Insert USERS list into the buffer.
+If NOTE is non-nil, include user's profile note.
+This is also called by `mastodon-tl--get-follow-suggestions'."
+ (mapc (lambda (el)
+ (insert (propertize (car el) 'face 'mastodon-display-name-face)
+ " : \n : "
+ (propertize (concat "@" (car (cdr el)))
+ 'face 'mastodon-handle-face
+ 'mouse-face 'highlight
+ 'mastodon-tab-stop 'user-handle
+ 'keymap mastodon-tl--link-keymap
+ 'mastodon-handle (concat "@" (car (cdr el)))
+ 'help-echo (concat "Browse user profile of @" (car (cdr el))))
+ " : \n"
+ (if note
+ (mastodon-tl--render-text (cadddr el) nil)
+ "")
+ "\n"))
+ users))
+
(defun mastodon-search--get-user-info (account)
- "Get user handle, display name and account URL from ACCOUNT."
+ "Get user handle, display name, account URL and profile note from ACCOUNT."
(list (alist-get 'display_name account)
(alist-get 'acct account)
- (alist-get 'url account)))
+ (alist-get 'url account)
+ (alist-get 'note account)))
(defun mastodon-search--get-hashtag-info (tag)
"Get hashtag name and URL from TAG."
diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el
index 758119c..cdb4aa2 100644
--- a/lisp/mastodon-tl.el
+++ b/lisp/mastodon-tl.el
@@ -2,10 +2,11 @@
;; Copyright (C) 2017-2019 Johnson Denen
;; Author: Johnson Denen <johnson.denen@gmail.com>
+;; Marty Hiatt <martianhiatus@riseup.net>
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
@@ -59,6 +60,7 @@
;; make notifications--get available via M-x and outside our keymap:
(autoload 'mastodon-notifications--get "mastodon-notifications"
"Display NOTIFICATIONS in buffer." t) ; interactive
+(autoload 'mastodon-search--insert-users-propertized "mastodon-search")
(defvar mastodon-instance-url)
(defvar mastodon-toot-timestamp-format)
(defvar shr-use-fonts) ;; declare it since Emacs24 didn't have this
@@ -462,22 +464,23 @@ By default it is `mastodon-tl--byline-boosted'"
The contents comes from the given TOOT which is used in parsing
links in the text. If TOOT is nil no parsing occurs."
- (with-temp-buffer
- (insert string)
- (let ((shr-use-fonts mastodon-tl--enable-proportional-fonts)
- (shr-width (when mastodon-tl--enable-proportional-fonts
- (- (window-width) 1))))
- (shr-render-region (point-min) (point-max)))
- ;; Make all links a tab stop recognized by our own logic, make things point
- ;; to our own logic (e.g. hashtags), and update keymaps where needed:
- (when toot
- (let (region)
- (while (setq region (mastodon-tl--find-property-range
- 'shr-url (or (cdr region) (point-min))))
- (mastodon-tl--process-link toot
- (car region) (cdr region)
- (get-text-property (car region) 'shr-url)))))
- (buffer-string)))
+ (when string ; handle rare empty notif server bug
+ (with-temp-buffer
+ (insert string)
+ (let ((shr-use-fonts mastodon-tl--enable-proportional-fonts)
+ (shr-width (when mastodon-tl--enable-proportional-fonts
+ (- (window-width) 1))))
+ (shr-render-region (point-min) (point-max)))
+ ;; Make all links a tab stop recognized by our own logic, make things point
+ ;; to our own logic (e.g. hashtags), and update keymaps where needed:
+ (when toot
+ (let (region)
+ (while (setq region (mastodon-tl--find-property-range
+ 'shr-url (or (cdr region) (point-min))))
+ (mastodon-tl--process-link toot
+ (car region) (cdr region)
+ (get-text-property (car region) 'shr-url)))))
+ (buffer-string))))
(defun mastodon-tl--process-link (toot start end url)
"Process link URL in TOOT as hashtag, userhandle, or normal link.
@@ -974,21 +977,42 @@ webapp"
(if (> (+ (length (alist-get 'ancestors context))
(length (alist-get 'descendants context)))
0)
- (with-output-to-temp-buffer buffer
- (switch-to-buffer buffer)
- (mastodon-mode)
- (setq mastodon-tl--buffer-spec
- `(buffer-name ,buffer
- endpoint ,(format "statuses/%s/context" id)
- update-function
- (lambda(toot) (message "END of thread."))))
- (let ((inhibit-read-only t))
- (mastodon-tl--timeline (vconcat
- (alist-get 'ancestors context)
- `(,toot)
- (alist-get 'descendants context)))))
+ (progn
+ (with-output-to-temp-buffer buffer
+ (switch-to-buffer buffer)
+ (mastodon-mode)
+ (setq mastodon-tl--buffer-spec
+ `(buffer-name ,buffer
+ endpoint ,(format "statuses/%s/context" id)
+ update-function
+ (lambda (toot) (message "END of thread."))))
+ (let ((inhibit-read-only t))
+ (mastodon-tl--timeline (vconcat
+ (alist-get 'ancestors context)
+ `(,toot)
+ (alist-get 'descendants context)))))
+ (mastodon-tl--goto-next-toot))
(message "No Thread!"))))
+(defun mastodon-tl--get-follow-suggestions ()
+"Display a buffer of suggested accounts to follow."
+ (interactive)
+ (let* ((buffer (format "*mastodon-follow-suggestions*"))
+ (response
+ (mastodon-http--get-json
+ (mastodon-http--api "suggestions")))
+ (users (mapcar 'mastodon-search--get-user-info response)))
+ (with-output-to-temp-buffer buffer
+ (let ((inhibit-read-only t))
+ (switch-to-buffer buffer)
+ (mastodon-mode)
+ (insert (mastodon-tl--set-face
+ (concat "\n ------------\n"
+ " SUGGESTED ACCOUNTS\n"
+ " ------------\n\n")
+ 'success))
+ (mastodon-search--insert-users-propertized users :note)))))
+
(defun mastodon-tl--follow-user (user-handle &optional notify)
"Query for USER-HANDLE from current status and follow that user.
If NOTIFY is \"true\", enable notifications when that user posts.
@@ -1092,7 +1116,7 @@ NOTIFY is only non-nil when called by `mastodon-tl--follow-user'."
;; if unmuting/unblocking, we got handle from mute/block list
(mastodon-profile--search-account-by-handle
user-handle)
- ;; if muting/blocking, we select from handles in current status
+ ;; if muting/blocking, we select from handles in current status
(mastodon-profile--lookup-account-in-status
user-handle (mastodon-profile--toot-json))))
(user-id (mastodon-profile--account-field account 'id))
@@ -1245,7 +1269,7 @@ is a no-op."
;; We need to re-schedule for an earlier time
(cancel-timer mastodon-tl--timestamp-update-timer)
(setq mastodon-tl--timestamp-update-timer
- (run-at-time this-update
+ (run-at-time (time-to-seconds (time-subtract this-update (current-time)))
nil ;; don't repeat
#'mastodon-tl--update-timestamps-callback
(current-buffer) nil)))))))
@@ -1298,7 +1322,9 @@ from the start if it is nil."
(copy-marker previous-timestamp))
;; otherwise we are done for now; schedule a new run for when needed
(setq mastodon-tl--timestamp-update-timer
- (run-at-time mastodon-tl--timestamp-next-update
+ (run-at-time (time-to-seconds
+ (time-subtract mastodon-tl--timestamp-next-update
+ (current-time)))
nil ;; don't repeat
#'mastodon-tl--update-timestamps-callback
buffer nil))))))))
@@ -1337,6 +1363,7 @@ JSON is the data returned from the server."
mastodon-tl--timestamp-next-update (time-add (current-time)
(seconds-to-time 300)))
(funcall update-function json))
+ (mastodon-tl--goto-next-toot)
(mastodon-mode)
(when (equal endpoint "follow_requests")
(mastodon-profile-mode))
@@ -1347,7 +1374,9 @@ JSON is the data returned from the server."
update-function ,update-function)
mastodon-tl--timestamp-update-timer
(when mastodon-tl--enable-relative-timestamps
- (run-at-time mastodon-tl--timestamp-next-update
+ (run-at-time (time-to-seconds
+ (time-subtract mastodon-tl--timestamp-next-update
+ (current-time)))
nil ;; don't repeat
#'mastodon-tl--update-timestamps-callback
(current-buffer)
@@ -1377,7 +1406,9 @@ Runs synchronously."
,update-function)
mastodon-tl--timestamp-update-timer
(when mastodon-tl--enable-relative-timestamps
- (run-at-time mastodon-tl--timestamp-next-update
+ (run-at-time (time-to-seconds
+ (time-subtract mastodon-tl--timestamp-next-update
+ (current-time)))
nil ;; don't repeat
#'mastodon-tl--update-timestamps-callback
(current-buffer)
diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el
index 746b7d4..3978e12 100644
--- a/lisp/mastodon-toot.el
+++ b/lisp/mastodon-toot.el
@@ -2,10 +2,11 @@
;; Copyright (C) 2017-2019 Johnson Denen
;; Author: Johnson Denen <johnson.denen@gmail.com>
+;; Marty Hiatt <martianhiatus@riseup.net>
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
diff --git a/lisp/mastodon.el b/lisp/mastodon.el
index f65a86d..a52bf41 100644
--- a/lisp/mastodon.el
+++ b/lisp/mastodon.el
@@ -5,7 +5,7 @@
;; Maintainer: Marty Hiatt <martianhiatus@riseup.net>
;; Version: 0.10.0
;; Package-Requires: ((emacs "27.1") (request "0.3.2") (seq "1.0"))
-;; Homepage: https://git.blast.noho.st/mouse/mastodon.el
+;; Homepage: https://codeberg.org/martianh/mastodon.el
;; This file is not part of GNU Emacs.
@@ -32,7 +32,6 @@
;;; Code:
(require 'cl-lib) ; for `cl-some' call in mastodon
-;; hack to make mastodon-toot customizes visible prior to running mastodon-toot:
(require 'mastodon-toot)
(declare-function discover-add-context-menu "discover")
diff --git a/test/mastodon-profile-tests.el b/test/mastodon-profile-tests.el
new file mode 100644
index 0000000..ca323ea
--- /dev/null
+++ b/test/mastodon-profile-tests.el
@@ -0,0 +1,288 @@
+;;; mastodon-profile-test.el --- Tests for mastodon-profile.el -*- lexical-binding: nil -*-
+
+(require 'el-mock)
+
+(defconst gargron-profile-json
+ '((id . "1")
+ (username . "Gargron")
+ (acct . "Gargron")
+ (display_name . "Eugen")
+ (locked . :json-false)
+ (bot . :json-false)
+ (discoverable . t)
+ (group . :json-false)
+ (created_at . "2016-03-16T00:00:00.000Z")
+ (note . "<p>Developer of Mastodon and administrator of mastodon.social. I post service announcements, development updates, and personal stuff.</p>")
+ (url . "https://mastodon.social/@Gargron")
+ (avatar . "https://files.mastodon.social/accounts/avatars/000/000/001/original/d96d39a0abb45b92.jpg")
+ (avatar_static . "https://files.mastodon.social/accounts/avatars/000/000/001/original/d96d39a0abb45b92.jpg")
+ (header . "https://files.mastodon.social/accounts/headers/000/000/001/original/c91b871f294ea63e.png")
+ (header_static . "https://files.mastodon.social/accounts/headers/000/000/001/original/c91b871f294ea63e.png")
+ (followers_count . 470905)
+ (following_count . 451)
+ (statuses_count . 70741)
+ (last_status_at . "2021-11-14")
+ (emojis . [])
+ (fields . [((name . "Patreon")
+ (value . "<a href=\"https://www.patreon.com/mastodon\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://www.</span><span class=\"\">patreon.com/mastodon</span><span class=\"invisible\"></span></a>")
+ (verified_at))
+ ((name . "Homepage")
+ (value . "<a href=\"https://zeonfederated.com\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">zeonfederated.com</span><span class=\"invisible\"></span></a>")
+ (verified_at . "2019-07-15T18:29:57.191+00:00"))])))
+
+(defconst ccc-profile-json
+ '((id . "369027")
+ (username . "CCC")
+ (acct . "CCC@social.bau-ha.us")
+ (display_name . "")
+ (locked . :json-false)
+ (bot . :json-false)
+ (discoverable . :json-false)
+ (group . :json-false)
+ (created_at . "2018-06-03T00:00:00.000Z")
+ (note . "<p><a href=\"https://www.ccc.de/\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://www.</span><span class=\"\">ccc.de/</span><span class=\"invisible\"></span></a></p>")
+ (url . "https://social.bau-ha.us/@CCC")
+ (avatar . "https://files.mastodon.social/cache/accounts/avatars/000/369/027/original/6cfeb310f40e041a.jpg")
+ (avatar_static . "https://files.mastodon.social/cache/accounts/avatars/000/369/027/original/6cfeb310f40e041a.jpg")
+ (header . "https://files.mastodon.social/cache/accounts/headers/000/369/027/original/0d20bef6131b8139.jpg")
+ (header_static . "https://files.mastodon.social/cache/accounts/headers/000/369/027/original/0d20bef6131b8139.jpg")
+ (followers_count . 2733)
+ (following_count . 120)
+ (statuses_count . 1357)
+ (last_status_at . "2021-11-02")
+ (emojis . [])
+ (fields . [])))
+
+(defconst gargon-statuses-json
+ `[((id . "123456789012345678")
+ (created_at . "2021-11-11T11:11:11.111Z")
+ (in_reply_to_id)
+ (in_reply_to_account_id)
+ (sensitive . :json-false)
+ (spoiler_text . "")
+ (visibility . "public")
+ (language)
+ (uri . "https://mastodon.social/users/Gargron/statuses/123456789012345678/activity")
+ (url . "https://mastodon.social/users/Gargron/statuses/123456789012345678/activity")
+ (replies_count . 0)
+ (reblogs_count . 0)
+ (favourites_count . 0)
+ (favourited . :json-false)
+ (reblogged . :json-false)
+ (muted . :json-false)
+ (bookmarked . :json-false)
+ (content . "<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>")
+ (reblog)
+ (application)
+ (account ,@gargron-profile-json)
+ (media_attachments . [])
+ (mentions . [])
+ (tags . [])
+ (emojis . [])
+ (card)
+ (poll))
+ ((id . "107279356043066700")
+ (created_at . "2021-11-11T00:00:00.000Z")
+ (in_reply_to_id)
+ (in_reply_to_account_id)
+ (sensitive . :json-false)
+ (spoiler_text . "")
+ (visibility . "public")
+ (language . "en")
+ (uri . "https://mastodon.social/users/Gargron/statuses/107279356043066700")
+ (url . "https://mastodon.social/@Gargron/107279356043066700")
+ (replies_count . 0)
+ (reblogs_count . 2)
+ (favourites_count . 0)
+ (favourited . :json-false)
+ (reblogged . :json-false)
+ (muted . :json-false)
+ (bookmarked . :json-false)
+ (content . "<p><span class=\"h-card\"><a href=\"https://social.bau-ha.us/@CCC\" class=\"u-url mention\">@<span>CCC</span></a></span> At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>")
+ (reblog)
+ (application
+ (name . "Web")
+ (website))
+ (account ,@gargron-profile-json)
+ (media_attachments . [])
+ (mentions . [((id . "369027")
+ (username . "CCC")
+ (url . "https://social.bau-ha.us/@CCC")
+ (acct . "CCC@social.bau-ha.us"))])
+ (tags . [])
+ (emojis . [])
+ (card)
+ (poll))])
+
+(ert-deftest mastodon-profile--add-author-bylines ()
+ "Should correctly format short infos about one account.
+
+When formatting Gargon's state we want to see
+- the short description of that profile,
+- the url of the avatar (yet to be loaded)
+- the info attached to the name"
+ (with-mock
+ ;; Don't start any image loading:
+ (mock (mastodon-media--inline-images * *) => nil)
+ ;; Let's not do formatting as that makes it hard to not rely on
+ ;; window width and reflowing the text.
+ (mock (shr-render-region * *) => nil)
+ (if (version< emacs-version "27.1")
+ (mock (image-type-available-p 'imagemagick) => t)
+ (mock (image-transforms-p) => t))
+
+ (with-temp-buffer
+ (let ((mastodon-tl--show-avatars t)
+ (mastodon-tl--display-media-p t))
+ (mastodon-profile--add-author-bylines (list gargron-profile-json)))
+
+ (should
+ (equal
+ (buffer-substring-no-properties (point-min) (point-max))
+ "\n Eugen (@Gargron)\n<p>Developer of Mastodon and administrator of mastodon.social. I post service announcements, development updates, and personal stuff.</p>\n"))
+
+ ;; Check the avatar at pos 2
+ (should
+ (equal
+ (get-text-property 2 'media-url)
+ "https://files.mastodon.social/accounts/avatars/000/000/001/original/d96d39a0abb45b92.jpg"))
+ (should
+ (equal
+ (get-text-property 2 'media-state)
+ 'needs-loading))
+
+ ;; Check the byline state
+ (should
+ (equal
+ (get-text-property 4 'byline)
+ t))
+ (should
+ (equal
+ (get-text-property 4 'toot-id)
+ (alist-get 'id gargron-profile-json)))
+ (should
+ (equal
+ (get-text-property 4 'toot-json)
+ gargron-profile-json)))))
+
+(ert-deftest mastodon-profile--search-account-by-handle--removes-at ()
+ "Should ignore a leading at-sign in user handle.
+
+The search will happen as if called without the \"@\"."
+ (with-mock
+
+ (mock (mastodon-http--get-json
+ "https://instance.url/api/v1/accounts/search?q=gargron"))
+
+ (let ((mastodon-instance-url "https://instance.url"))
+ ;; We don't check anything from the return value. We only care
+ ;; that the mocked fetch was called with the expected URL.
+ (mastodon-profile--search-account-by-handle "@gargron"))))
+
+(ert-deftest mastodon-profile--search-account-by-handle--filters-out-false-results ()
+ "Should ignore results that don't match the searched handle."
+ (with-mock
+ (mock (mastodon-http--get-json *)
+ =>
+ (vector ccc-profile-json gargron-profile-json))
+
+ (let ((mastodon-instance-url "https://instance.url"))
+ (should
+ (equal
+ (mastodon-profile--search-account-by-handle "Gargron")
+ gargron-profile-json)))))
+
+(ert-deftest mastodon-profile--search-account-by-handle--filtering-is-case-sensitive ()
+ "Should ignore results that don't match the searched handle with exact case.
+
+TODO: We need to decide if this is actually desired or not."
+ (with-mock
+ (mock (mastodon-http--get-json *) => (vector gargron-profile-json))
+
+ (let ((mastodon-instance-url "https://instance.url"))
+ (should
+ (null
+ (mastodon-profile--search-account-by-handle "gargron"))))))
+
+(ert-deftest mastodon-profile--account-from-id--correct-url ()
+ "Should use the expected url for looking up by account id."
+ (with-mock
+
+ (mock (mastodon-http--get-json
+ "https://instance.url/api/v1/accounts/1234567"))
+
+ (let ((mastodon-instance-url "https://instance.url"))
+ ;; We don't check anything from the return value. We only care
+ ;; that the mocked fetch was called with the expected URL.
+ (mastodon-profile--account-from-id "1234567"))))
+
+(ert-deftest mastodon-profile--make-author-buffer ()
+ "Should set up the buffer as expected for the given author.
+
+This is a far more complicated test as the
+mastodon-profile--make-author-buffer function does so much. There
+is a bit too much mocking and this may be brittle but it should
+help identify when things change unexpectedly.
+
+TODO: Consider separating the data retrieval and the actual
+content generation in the function under test."
+ (with-mock
+ ;; Don't start any image loading:
+ (mock (mastodon-media--inline-images * *) => nil)
+ (if (version< emacs-version "27.1")
+ (mock (image-type-available-p 'imagemagick) => t)
+ (mock (image-transforms-p) => t))
+ (mock (mastodon-http--get-json "https://instance.url/api/v1/accounts/1/statuses")
+ =>
+ gargon-statuses-json)
+ (mock (mastodon-profile--get-statuses-pinned *)
+ =>
+ [])
+ (mock (mastodon-profile--relationships-get "1")
+ =>
+ [((id . "1") (following . :json-false) (showing_reblogs . :json-false) (notifying . :json-false) (followed_by . :json-false) (blocking . :json-false) (blocked_by . :json-false) (muting . :json-false) (muting_notifications . :json-false) (requested . :json-false) (domain_blocking . :json-false) (endorsed . :json-false) (note . ""))])
+ ;; Let's not do formatting as that makes it hard to not rely on
+ ;; window width and reflowing the text.
+ (mock (shr-render-region * *) => nil)
+ ;; Don't perform the actual update call at the end.
+ ;;(mock (mastodon-tl--timeline *))
+
+ (let ((mastodon-tl--show-avatars t)
+ (mastodon-tl--display-media-p t)
+ (mastodon-instance-url "https://instance.url"))
+ (mastodon-profile--make-author-buffer gargron-profile-json)
+
+ (should
+ (equal
+ (buffer-substring-no-properties (point-min) (point-max))
+ (concat
+ "\n"
+ "[img] \n"
+ "Eugen\n"
+ "@Gargron\n"
+ " ------------\n"
+ "<p>Developer of Mastodon and administrator of mastodon.social. I post service announcements, development updates, and personal stuff.</p>\n"
+ "_ Patreon __ :: <a href=\"https://www.patreon.com/mastodon\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://www.</span><span class=\"\">patreon.com/mastodon</span><span class=\"invisible\"></span></a>_ Homepage _ :: <a href=\"https://zeonfederated.com\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">zeonfederated.com</span><span class=\"invisible\"></span></a>\n"
+ " ------------\n"
+ " TOOTS: 70741 | FOLLOWERS: 470905 | FOLLOWING: 451\n"
+ " ------------\n"
+ "\n"
+ " ------------\n"
+ " TOOTS \n"
+ " ------------\n"
+ "\n"
+ "<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p> \n"
+ " Eugen (@Gargron) 2021-11-11 12:11:11\n"
+ " ------------\n"
+ "\n"
+ "\n"
+ "<p><span class=\"h-card\"><a href=\"https://social.bau-ha.us/@CCC\" class=\"u-url mention\">@<span>CCC</span></a></span> At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p> \n"
+ " Eugen (@Gargron) 2021-11-11 01:00:00\n"
+ " ------------\n"
+ "\n"
+ )))
+
+ ;; Until the function gets refactored this creates a non-temp
+ ;; buffer with Gargron's statuses which we want to delete (if
+ ;; the tests succeed).
+ (kill-buffer))))
diff --git a/test/mastodon-search-tests.el b/test/mastodon-search-tests.el
index 996f786..e6d4cdb 100644
--- a/test/mastodon-search-tests.el
+++ b/test/mastodon-search-tests.el
@@ -126,7 +126,10 @@
(should
(equal
(mastodon-search--get-user-info mastodon-search--single-account-query)
- '(": ( ) { : | : & } ; :" "mousebot" "https://todon.nl/@mousebot"))))
+ '(": ( ) { : | : & } ; :"
+ "mousebot"
+ "https://todon.nl/@mousebot"
+ "<p>poetry, writing, dmt, desertion, trash, black metal, translation, hegel, language, autonomia....</p><p><a href=\"https://anarchive.mooo.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">anarchive.mooo.com</span><span class=\"invisible\"></span></a><br /><a href=\"https://pleasantlybabykid.tumblr.com/\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">pleasantlybabykid.tumblr.com/</span><span class=\"invisible\"></span></a><br />IG: <a href=\"https://bibliogram.snopyta.org/u/martianhiatus\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">bibliogram.snopyta.org/u/marti</span><span class=\"invisible\">anhiatus</span></a><br />photos alt: <span class=\"h-card\"><a href=\"https://todon.eu/@goosebot\" class=\"u-url mention\">@<span>goosebot</span></a></span><br />git: <a href=\"https://git.blast.noho.st/mouse\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">git.blast.noho.st/mouse</span><span class=\"invisible\"></span></a></p><p>want to trade chapbooks or zines? hmu!</p><p>he/him or they/them</p>"))))
(ert-deftest mastodon-search--get-hashtag-info ()
"Should build a list of hashtag name and URL."
diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el
index dd07416..a569c89 100644
--- a/test/mastodon-tl-tests.el
+++ b/test/mastodon-tl-tests.el
@@ -559,7 +559,7 @@ a string or a numeric."
(mock (mastodon-tl--relative-time-details 'fake-timestamp) =>
(cons "xxx ago" soon-in-the-future))
(mock (cancel-timer 'initial-timer))
- (mock (run-at-time soon-in-the-future nil
+ (mock (run-at-time * nil
#'mastodon-tl--update-timestamps-callback
(current-buffer) nil) => 'new-timer)