;;; gnus-mock.el --- Mock Gnus installation for testing -*- lexical-binding: t; -*-
;; Copyright (C) 2018 Free Software Foundation
;; Author: Eric Abrahamsen
;; 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 .
;;; Commentary:
;; This module provides a reproducible mock Gnus installation,
;; including dummy data, that can be used for Gnus development and
;; testing. Start the mock Gnus session with either `gnus-mock' or
;; `gnus-mock-unplugged'. Nothing in the mock sessions will make a
;; network connection, and mail sending is stubbed out using
;; `gnus-mock-sendmail-program'.
;; The mock session starts with a predefined nnmaildir server, as well
;; as some dummy mail data. Other predefined servers may be added in
;; the future. At startup, all dummy data is copied into a temporary
;; directory. At shutdown, the temporary directory is deleted.
;; A special config file is used for the mock session; users may add
;; to this config, or shadow its options, by setting
;; `gnus-mock-settings-file' to the name of an additional config file.
;;; Code:
(require 'gnus)
(require 'message)
(defgroup gnus-mock nil
"Options for the mock Gnus installation."
:group 'gnus
:version "27.1")
(defcustom gnus-mock-settings-file nil
"Path to an additional config file for mock Gnus.
The contents of this file will be appended to gnus-mock's own
config file before Gnus startup, in effect shadowing config
values in the default file."
:group 'gnus-mock
:type 'file)
(defcustom gnus-mock-data-dir
(expand-file-name "test/data/gnus/mock" source-directory)
"Source directory for Gnus mock data."
:group 'gnus-mock
:type 'string)
(defcustom gnus-mock-cleanup-p t
"When non-nil, delete temporary files after shutdown.
Each Gnus mock session will create a new temporary directory, so
multiple sessions will not conflict if this option is nil."
:group 'gnus-mock
:type 'boolean)
(defcustom gnus-mock-sendmail-program
(nnheader-concat gnus-mock-data-dir "fakesendmail.py")
"Program used as the value of `sendmail-program'."
:group 'gnus-mock
:type 'string)
;; Regular Gnus can also check this, in case of a "dirty" mock
;; session.
(defvar gnus-mock-p nil
"Non-nil during a mocked Gnus session.")
(defun gnus-mock-setup ()
"Set up mock data and config."
(let ((mock-tmp-dir (make-temp-file "emacs-gnus-mock-" t)))
(setq gnus-home-directory mock-tmp-dir
gnus-directory (nnheader-concat gnus-home-directory "News")
gnus-agent-directory (nnheader-concat gnus-directory "agent/")
nndraft-directory (nnheader-concat gnus-directory "drafts/")
gnus-init-file (nnheader-concat gnus-home-directory ".gnus")
gnus-startup-file (nnheader-concat gnus-home-directory ".newsrc")
message-directory gnus-home-directory
sendmail-program gnus-mock-sendmail-program
;; If Emacs was started with -Q, as it should have been,
;; `init-file-user' will be nil which will prevent reading of
;; `gnus-init-file'.
init-file-user "gnus-mock")
;; Put our data and config in place.
(copy-directory
gnus-mock-data-dir
(file-name-as-directory gnus-home-directory) nil nil t)
;; Possibly insert additional config.
(when gnus-mock-settings-file
(with-temp-buffer
(insert-file-contents gnus-mock-settings-file)
(append-to-file
(point-min) (point-max) gnus-init-file)))))
;;;###autoload
(defun gnus-mock-unplugged ()
"Start an unplugged mock Gnus session."
(interactive)
(gnus-mock t))
;;;###autoload
(defun gnus-mock (&optional unplugged)
"Start a mock Gnus session."
(interactive)
(when (gnus-alive-p)
(error "First save and quit your running Gnus session"))
(gnus-mock-setup)
(when unplugged
(setq gnus-plugged nil))
(setq gnus-mock-p t)
(gnus)
(add-hook 'gnus-after-exiting-gnus-hook #'gnus-mock-restore))
(defun gnus-mock-restore ()
"Restore after quitting a mock Gnus session."
(when gnus-mock-p
(when gnus-mock-cleanup-p
(delete-directory gnus-home-directory t))
(setq gnus-mock-p nil)
(remove-hook 'gnus-after-exiting-gnus-hook #'gnus-mock-restore)))
(provide 'gnus-mock)
;;; gnus-mock.el ends here