(defvar-local erc-dbuf nil)
+;; See comments in `erc-scenarios-base-local-modules' explaining why
+;; this is insufficient as a public interface.
+
+(defvar erc--target-priors nil
+ "Analogous to `erc--server-reconnecting' but for target buffers.
+Bound to local variables from an existing (logical) session's
+buffer during local-module setup and `erc-mode-hook' activation.")
+
(defun erc--target-from-string (string)
"Construct an `erc--target' variant from STRING."
(funcall (if (erc-channel-p string)
(let* ((target (and channel (erc--target-from-string channel)))
(buffer (erc-get-buffer-create server port nil target id))
(old-buffer (current-buffer))
- (old-vars (and target (buffer-local-variables)))
+ (erc--target-priors (and target ; buf from prior session
+ (buffer-local-value 'erc--target buffer)
+ (buffer-local-variables buffer)))
(old-recon-count erc-server-reconnect-count)
(old-point nil)
(delayed-modules nil)
(setq old-point (point))
(setq delayed-modules
(erc--merge-local-modes (erc--update-modules)
- (or erc--server-reconnecting old-vars)))
+ (or erc--server-reconnecting
+ erc--target-priors)))
(delay-mode-hooks (erc-mode))
;;; Commentary:
-;; These tests all use `sasl' because, as of ERC 5.5, it's the one
-;; and only local module.
+;; A local module doubles as a minor mode whose mode variable and
+;; associated local data can withstand service disruptions.
+;; Unfortunately, the current implementation is too unwieldy to be
+;; made public because it doesn't perform any of the boiler plate
+;; needed to save and restore buffer-local and "network-local" copies
+;; of user options. Ultimately, a user-friendly framework must fill
+;; this void if third-party local modules are ever to become
+;; practical.
+;;
+;; The following tests all use `sasl' because, as of ERC 5.5, it's the
+;; only local module.
;;; Code:
(erc-cmd-QUIT "")
(funcall expect 10 "finished")))
- (ert-info ("Disabling works from a target buffer.")
+ (ert-info ("Disabling works from a target buffer")
(with-current-buffer "#chan"
(should erc-sasl-mode)
(call-interactively #'erc-sasl-disable)
(should (local-variable-p 'erc-sasl-mode))
(should-not (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
(erc-cmd-RECONNECT)
- (with-current-buffer "#chan"
- (funcall expect 10 "Some enigma, some riddle")
- (should-not erc-sasl-mode) ; regression
- (should (local-variable-p 'erc-sasl-mode))))
+ (funcall expect 10 "Some enigma, some riddle")
+ (should-not erc-sasl-mode) ; regression
+ (should (local-variable-p 'erc-sasl-mode)))
(with-current-buffer "foonet"
(should (local-variable-p 'erc-sasl-mode))
(should erc-sasl-mode)
(funcall expect 10 "User modes for tester")))))
+(defvar-local erc-scenarios-base-local-modules--local-var nil)
+
+(define-erc-module -phony-sblm- nil
+ "Test module for `erc-scenarios-base-local-modules--var-persistence'."
+ ((when-let ((vars (or erc--server-reconnecting erc--target-priors)))
+ (should (assq 'erc--phony-sblm--mode vars))
+ (setq erc-scenarios-base-local-modules--local-var
+ (alist-get 'erc-scenarios-base-local-modules--local-var vars)))
+ (setq erc-scenarios-base-local-modules--local-var
+ (or erc-scenarios-base-local-modules--local-var
+ (if erc--target 100 0))))
+ ((kill-local-variable 'erc-scenarios-base-local-modules--local-var))
+ 'local)
+
+;; Note: this file has grown too expensive (time-wise) and must be
+;; split up. When that happens, this test should be rewritten without
+;; any time-saving hacks, namely, server-initiated JOINs and an
+;; absence of QUITs. (That said, three connections in under 2 seconds
+;; is pretty nice.)
+
+(ert-deftest erc-scenarios-base-local-modules--var-persistence ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/reconnect")
+ (erc-server-flood-penalty 0.1)
+ (dumb-server (erc-d-run "localhost" t 'options 'options 'options))
+ (port (process-contact dumb-server :service))
+ (erc-modules (cons '-phony-sblm- (remq 'autojoin erc-modules)))
+ (expect (erc-d-t-make-expecter))
+ (server-buffer-name (format "127.0.0.1:%d" port)))
+
+ (ert-info ("Initial authentication succeeds as expected")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+ (should (string= (buffer-name) server-buffer-name)))
+
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "FooNet"))
+ (funcall expect 10 "This server is in debug mode")
+ (should erc--phony-sblm--mode)
+ (should (eql erc-scenarios-base-local-modules--local-var 0))
+ (setq erc-scenarios-base-local-modules--local-var 1)))
+
+ (ert-info ("Save module's local var in target buffer")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+ (should (eql erc-scenarios-base-local-modules--local-var 100))
+ (setq erc-scenarios-base-local-modules--local-var 101)
+ (funcall expect 20 "welcome")))
+
+ (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
+
+ (ert-info ("Vars reused when mode was left enabled")
+ (with-current-buffer "#chan"
+ (erc-cmd-RECONNECT)
+ (funcall expect 20 "welcome")
+ (should (eql erc-scenarios-base-local-modules--local-var 101))
+ (erc--phony-sblm--mode -1))
+
+ (with-current-buffer "FooNet"
+ (funcall expect 10 "User modes for tester")
+ (should (eql erc-scenarios-base-local-modules--local-var 1))))
+
+ (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
+
+ (ert-info ("Local binding gone when mode disabled in target")
+ (with-current-buffer "#chan"
+ (erc-cmd-RECONNECT)
+ (funcall expect 20 "welcome")
+ (should-not erc--phony-sblm--mode)
+ (should-not erc-scenarios-base-local-modules--local-var))
+
+ ;; But value retained in server buffer, where mode is active.
+ (with-current-buffer "FooNet"
+ (funcall expect 10 "User modes for tester")
+ (should (eql erc-scenarios-base-local-modules--local-var 1))))))
+
;;; erc-scenarios-local-modules.el ends here