[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
fix/bug-48598 c2943fec8e 1/2: [CATCH-UP] Synchronize with patch set
From: |
F. Jason Park |
Subject: |
fix/bug-48598 c2943fec8e 1/2: [CATCH-UP] Synchronize with patch set |
Date: |
Wed, 4 May 2022 02:30:46 -0400 (EDT) |
branch: fix/bug-48598
commit c2943fec8eac4039a7069cacbd4224f91adae0ed
Author: F. Jason Park <jp@neverwas.me>
Commit: F. Jason Park <jp@neverwas.me>
[CATCH-UP] Synchronize with patch set
Note: this branch exists for testing purposes and not for code sharing
or merging. The bug fix continues to be developed as a series of
discrete patches (see email thread for download link). Commits like
this apply recent changes from the bug set, basically an "--interdiff"
or "--range-diff" from git-format-patch(1). Non-ERC parts of the tree
are behind master.
This also includes the following from master, but only the hunks that
touch lisp/erc, test/lisp/erc, doc/misc/erc.texi, or etc/ERC-NEWS:
* 2d71fd3b04 Further doc string quoting fixes
* bbf389ea6d Audit quoting the quote character in doc strings
---
doc/misc/erc.texi | 151 +-
lisp/erc/erc-backend.el | 16 +-
lisp/erc/erc-compat.el | 86 -
lisp/erc/erc-join.el | 6 +-
lisp/erc/erc-networks.el | 21 +-
lisp/erc/erc-services.el | 19 +-
lisp/erc/erc.el | 235 +-
.../erc-d/erc-d-self-resources/proxy-subprocess.el | 26 -
test/lisp/erc/erc-join-tests.el | 40 +-
test/lisp/erc/erc-scenarios-common.el | 152 --
test/lisp/erc/erc-scenarios.el | 2312 --------------------
.../erc/{erc-d => erc-scenarios}/erc-d-self.el | 89 +-
.../erc/erc-scenarios/erc-scenarios-auth-source.el | 178 ++
.../erc-scenarios-base-association-nick.el | 164 ++
.../erc-scenarios-base-association-samenet.el | 144 ++
.../erc-scenarios-base-association.el | 196 ++
.../erc-scenarios-base-compat-rename-bouncer.el | 175 ++
.../erc-scenarios-base-misc-regressions.el | 135 ++
.../erc-scenarios-base-netid-bouncer-id.el | 34 +
.../erc-scenarios-base-netid-bouncer-recon-base.el | 30 +
.../erc-scenarios-base-netid-bouncer-recon-both.el | 32 +
.../erc-scenarios-base-netid-bouncer-recon-id.el | 35 +
.../erc-scenarios-base-netid-bouncer.el | 35 +
.../erc-scenarios-base-netid-samenet.el | 147 ++
.../erc-scenarios/erc-scenarios-base-reconnect.el | 227 ++
.../erc/erc-scenarios/erc-scenarios-base-renick.el | 310 +++
.../erc-scenarios-base-reuse-buffers.el | 189 ++
.../erc-scenarios/erc-scenarios-base-unstable.el | 137 ++
.../erc-scenarios-join-netid-newcmd-id.el | 50 +
.../erc-scenarios-join-netid-newcmd.el | 37 +
.../erc-scenarios-join-netid-recon-id.el | 46 +
.../erc-scenarios-join-netid-recon.el | 36 +
test/lisp/erc/erc-scenarios/erc-scenarios-misc.el | 145 ++
.../erc-scenarios/erc-scenarios-services-misc.el | 86 +
.../base/association/bouncer-history/barnet.eld | 2 +-
.../base/association/bouncer-history/foonet.eld | 0
.../base/association/multi-net/barnet.eld | 2 +-
.../base/association/multi-net/foonet.eld | 2 +-
.../base/association/nick-bump/renicked-again.eld | 4 +-
.../nick-bump/renicked-foisted-again.eld | 0
.../association/nick-bump/renicked-foisted.eld | 0
.../base/association/nick-bump/renicked.eld | 2 +-
.../reconnect-playback/foonet-again.eld | 4 +-
.../base/association/reconnect-playback/foonet.eld | 6 +-
.../base/association/same-network/chester.eld | 2 +-
.../base/association/same-network/tester-again.eld | 2 +-
.../base/association/same-network/tester.eld | 2 +-
.../resources}/base/auth-source/foonet.eld | 0
.../resources}/base/auth-source/nopass.eld | 0
.../base/channel-buffer-revival/foonet.eld | 2 +-
.../resources}/base/flood/soju.eld | 0
.../resources}/base/gapless-connect/barnet.eld | 2 +-
.../resources}/base/gapless-connect/foonet.eld | 2 +-
.../resources}/base/gapless-connect/pass-stub.eld | 0
.../resources}/base/mask-target-routing/foonet.eld | 0
.../base/network-id/bouncer/barnet-again.eld | 10 +-
.../base/network-id/bouncer/barnet-drop.eld | 2 +-
.../resources}/base/network-id/bouncer/barnet.eld | 10 +-
.../base/network-id/bouncer/foonet-again.eld | 8 +-
.../base/network-id/bouncer/foonet-drop.eld | 2 +-
.../resources}/base/network-id/bouncer/foonet.eld | 10 +-
.../base/network-id/bouncer/stub-again.eld | 0
.../base/network-id/same-network/chester.eld | 2 +-
.../base/network-id/same-network/tester.eld | 2 +-
.../resources}/base/reconnect/aborted-dupe.eld | 0
.../resources}/base/reconnect/aborted.eld | 0
.../resources}/base/reconnect/options-again.eld | 0
.../resources}/base/reconnect/options.eld | 0
.../resources}/base/reconnect/timer-last.eld | 0
.../resources}/base/reconnect/timer.eld | 0
.../base/renick/queries/bouncer-barnet.eld | 10 +-
.../base/renick/queries/bouncer-foonet.eld | 4 +-
.../resources}/base/renick/queries/solo.eld | 2 +-
.../resources}/base/renick/self/auto.eld | 4 +-
.../resources}/base/renick/self/manual.eld | 0
.../resources}/base/renick/self/qual-chester.eld | 0
.../resources}/base/renick/self/qual-tester.eld | 0
.../base/reuse-buffers/channel-buffers/barnet.eld | 10 +-
.../base/reuse-buffers/channel-buffers/foonet.eld | 4 +-
.../base/reuse-buffers/server-buffers/barnet.eld | 2 +-
.../base/reuse-buffers/server-buffers/foonet.eld | 2 +-
.../{ => erc-scenarios/resources}/erc-d/erc-d-i.el | 0
.../{ => erc-scenarios/resources}/erc-d/erc-d-t.el | 9 +-
.../{ => erc-scenarios/resources}/erc-d/erc-d-u.el | 2 +-
.../{ => erc-scenarios/resources}/erc-d/erc-d.el | 33 +-
.../resources/erc-d/resources}/basic.eld | 0
.../resources/erc-d/resources}/depleted.eld | 0
.../resources/erc-d/resources}/drop-a.eld | 0
.../resources/erc-d/resources}/drop-b.eld | 0
.../resources/erc-d/resources}/dynamic-barnet.eld | 0
.../resources/erc-d/resources}/dynamic-foonet.eld | 0
.../resources/erc-d/resources}/dynamic-stub.eld | 0
.../resources/erc-d/resources}/dynamic.eld | 8 +-
.../resources/erc-d/resources}/eof.eld | 0
.../resources/erc-d/resources}/fuzzy.eld | 0
.../resources/erc-d/resources}/incremental.eld | 0
.../erc-d/resources}/irc-parser-tests.eld | 0
.../resources/erc-d/resources}/linger-multi-a.eld | 0
.../resources/erc-d/resources}/linger-multi-b.eld | 0
.../resources/erc-d/resources}/linger.eld | 0
.../resources/erc-d/resources}/no-block.eld | 2 +-
.../resources/erc-d/resources}/no-match.eld | 0
.../resources/erc-d/resources}/no-pong.eld | 0
.../resources/erc-d/resources}/nonstandard.eld | 0
.../resources/erc-d/resources}/proxy-barnet.eld | 0
.../resources/erc-d/resources}/proxy-foonet.eld | 0
.../resources/erc-d/resources}/proxy-solo.eld | 0
.../resources/erc-d/resources/proxy-subprocess.el | 45 +
.../resources/erc-d/resources}/timeout.eld | 0
.../resources/erc-d/resources}/unexpected.eld | 0
.../resources/erc-scenarios-common.el | 467 ++++
.../resources}/join/legacy/foonet.eld | 0
.../resources}/join/network-id/barnet.eld | 2 +-
.../resources}/join/network-id/foonet-again.eld | 4 +-
.../resources}/join/network-id/foonet.eld | 8 +-
.../resources}/join/reconnect/foonet-again.eld | 0
.../resources}/join/reconnect/foonet.eld | 0
.../networks/announced-missing/foonet.eld | 0
.../resources}/services/auth-source/libera.eld | 0
.../resources}/services/password/libera.eld | 0
test/lisp/erc/erc-services-tests.el | 634 ++++--
test/lisp/erc/erc-tests.el | 59 +-
122 files changed, 4005 insertions(+), 3107 deletions(-)
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index b96e3d886d..22e27c411e 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -752,9 +752,9 @@ string abiding by the rules of the network.
@cindex password
@defopt erc-prompt-for-password
-If non-@code{nil} (the default), @kbd{M-x erc} prompts for a server
-password. This only affects interactive invocations of @code{erc} and
-@code{erc-tls}.
+If non-@var{nil} (the default), @kbd{M-x erc @key{RET}} prompts for a
+server password. This only affects interactive invocations of
+@command{erc} and @command{erc-tls}.
@end defopt
@noindent
@@ -769,32 +769,29 @@ machine irc.example.net login mynick password sEcReT
@noindent
Here, @code{irc.example.net} corresponds to the @var{server} param
-passed to @code{erc} or @code{erc-tls} or provideed at the ``IRC
+passed to @command{erc} or @command{erc-tls} or provideed at the ``IRC
server:'' prompt. Unfortunately, specifying a network, like
-``Libera.Chat'', or a specific network server, like
-@code{zirconium.libera.chat}, won't work for this introductory
-exchange because IRC servers don't provide such information up front.
+``Libera.Chat,'' or a specific network server, like
+``zirconium.libera.chat,'' won't work for this introductory exchange
+because IRC servers don't provide such information up front.
If ERC can't find a suitable server password, it'll just skip the IRC
-@code{PASS} command altogether, something users may want when using
+``PASS'' command altogether, something users may want when using
CertFP or engaging NickServ via ERC's ``services'' module. If that
-sounds like you, set the option @code{erc-connect-auth-source-host} to
-@code{nil}. You can also set it to @code{t} to tell ERC to favor a
-``network identifier'' (corresponding to the @var{id} parameter of
-@code{erc-tls}) as the ``machine'' field and to fall back on
-@var{server} when an @var{id} hasn't been provided. Note that some
-networks and IRCds may support account-services authentication via
-server password when specified using the non-standard
-``mynick:sEcReT'' convention.
+sounds like you, set the option
+@code{erc-auth-source-parameters-server-function} to @code{nil}. Note
+that some networks and IRCds may support account-services
+authentication via server password when specified using the
+non-standard ``mynick:sEcReT'' convention.
@code{auth-source} can also be used to authenticate to account
services the traditional way, through a bot called ``NickServ''. To
tell ERC to do that, set the option
@code{erc-use-auth-source-for-nickserv-password} to @code{t}. For
these queries, entries featuring user-provided IDs and networks are
-matched first, followed by network-specific servers and dialed TCP
-endpoints (the @var{SERVER} passed to @code{erc}). The following
-netrc-style entries appear in order of precedence:
+matched first, followed by network-specific servers and dialed
+endpoints (typically, the @var{SERVER} passed to @command{erc}). The
+following netrc-style entries appear in order of precedence:
@example
machine Libera/cellphone login "mynick" password sEcReT
@@ -803,21 +800,74 @@ machine zirconium.libera.chat login "mynick" password
sEcReT
machine irc.libera.chat login "mynick" password sEcReT
@end example
-@noindent
-To modify this behavior, for example by signaling an error instead of
-degrading gracefully (which may feel like anything but, depending on
-your use case), see option @code{erc-auth-source-parameters-function}.
+If this fallback stuff doesn't appeal to you, see the option
+@code{erc-auth-source-parameters-server-function} and friends just
+below. These let you decide based on context how a connection's
+parameters should map to auth-source queries. But most users can just
+ignore all the details and get by with something like the following as
+values:
+
+@example
+(defun my-erc-auth-source-server (&rest _)
+ (list :host "MyHost"))
+
+;; or
+
+(defun my-erc-auth-source-services (&rest _)
+ (list :host (read-string "Auth-source host: ")))
+@end example
+
+ERC also consults @code{auth-source} to find ``keys'' that may be
+required by certain channels you join. When modifying a traditional
+@code{auth-source} entry for such use, put the channel name, for
+example ``##my-plus-k-chan,'' in the value of the ``user'' field (also
+known as the ``login'' field). The actual key goes in the ``password''
+(or ``secrets'') field.
+
+For details, @pxref{Top,,auth-source, auth, Emacs auth-source Library}.
+
+@defopt erc-auth-source-parameters-server-function
+@end defopt
+@defopt erc-auth-source-parameters-services-function
+@end defopt
+@defopt erc-auth-source-parameters-join-function
-ERC also consults @code{auth-source} to find any channel keys required
-for the channels that you wish to autojoin, as specified by the
-variable @code{erc-autojoin-channels-alist}. When modifying a
-netrc-style @code{auth-source} file for such use, ensure an entry
-exists with the channel name, for example ``#erc'', in the value of
-the ``login'' field (also known as the ``user'' field). The actual key
-goes in the ``password'' field.
+ERC calls these functions with keyword arguments recognized by
+`auth-source-search', namely, those deemed most relevant to the
+current context. For example, with NickServ queries, @code{:user}
+will be the ``desired'' nickname rather than the current one.
+Generalized names, like @code{:user} and @code{:host}, are always used
+over back-end specific ones, like @code{:login} or @code{:machine}.
+ERC expects a refined plist in return.
-For more details, @pxref{Top,,auth-source, auth, Emacs auth-source Library}.
+The ordering of the returned pairs influences how results are filtered
+as does the ordering of the members of any individual composite
+values. If necessary, the former (pairs) takes priority over the
+latter (values). For example, if the function returns
+@example
+(:host (foo bar) :port (123 456))
+@end example
+
+the secret from an auth-source entry of host foo and port 456 will be
+chosen over another of host bar and port 123. However, if the
+function returns
+
+@example
+(:port (123 456) :host (foo bar))
+@end example
+
+the opposite will be true. In both cases, two entries with the same
+host but different ports would see the one with port 123 being
+selected. Much the same would happen for entries sharing only a port:
+the one with host foo would win.
+
+Some auth-source back ends may not be compatible; netrc, plstore,
+json, and secrets are currently supported.
+
+The default value for all variants is currently
+@code{erc-auth-source-determine-params-merge}.
+@end defopt
@subheading Full name
@@ -844,26 +894,25 @@ This can be either a string or a function to call.
@subheading ID
-Every IRC connection has a ``network identifier''. It's an abstract
-concept used internally for referring to a connection, primarily for
-the purpose of wrangling buffers. An ID is normally derived from a
-combination of logical and physical connection parameters (typically
-IRC and TCP, respectively). Explicitly providing one to an
-entry-point function (like @code{erc-tls}) is rarely needed except in
-rare situations where ERC would otherwise have trouble discerning
-between connections.
-
-One such situation would be to allow multiple connections to the same
-network with the same nick but different (non-standard) "device"
-identifiers, which some bouncers may support. Another might be to
-mimic the experience of popular standalone clients, which normally
-offer ``named'' persistent configurations with server buffers
-reflecting those names. Yet another use case might involve
-third-party code needing to identify a connection unequivocally but in
-a human-friendly way devoid of noisy suffixes.
-
-Strings and symbols make the most sense when providing an ID as an
-entry-point argument, but any printable object is acceptable.
+ERC uses an abstract designation called a ``network identifier'' for
+referring to a connection internally. While normally derived from a
+combination of logical and physical connection parameters, an ID can
+also be explicitly provided via an entry-point command (like
+@command{erc-tls}). Use this in rare situations where ERC would
+otherwise have trouble discerning between connections.
+
+One such situation might see multiple connections to the same network
+using the same nick but different (non-standard) "device" identifiers,
+which some bouncers may support. Another might be to mimic the
+experience offered by popular standalone clients, which normally offer
+``named'' persistent configurations with server buffers reflecting
+those names. Yet another use case might involve third-party code
+needing to identify a connection unequivocally but in a human-friendly
+way suitable for UI components.
+
+When providing an ID as an entry-point argument, strings and symbols
+make the most sense, but any reasonably printable object is
+acceptable.
@node Sample Configuration
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 1335ee41fb..34de5d48b9 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -479,7 +479,7 @@ If POS is out of range, the value is nil."
(defun erc-bounds-of-word-at-point ()
"Return the bounds of word at point, or nil if we're not at a word.
If no `subword-mode' is active, then this is
-\(bounds-of-thing-at-point 'word)."
+\(bounds-of-thing-at-point \\='word)."
(if (or (erc-word-at-arg-p (point))
(erc-word-at-arg-p (1- (point))))
(save-excursion
@@ -732,14 +732,20 @@ Conditionally try to reconnect and take appropriate
action."
(erc-with-all-buffers-of-server
proc nil ; sorta wish this was indent 2
(when (and erc-hide-prompt
- (memq erc-hide-prompt
- (list t (if (erc-default-target) 'target 'server)))
+ (or (eq erc-hide-prompt t)
+ ;; FIXME use `erc--target' after bug#48598
+ (memq (if (erc-default-target)
+ (if (erc-channel-p (car erc-default-recipients))
+ 'channel
+ 'query)
+ 'server)
+ erc-hide-prompt))
(marker-position erc-insert-marker)
(marker-position erc-input-marker)
(get-text-property erc-insert-marker 'erc-prompt))
(with-silent-modifications
- (add-text-properties erc-insert-marker
- erc-input-marker `(display ,erc-prompt-hidden)))
+ (add-text-properties erc-insert-marker (1- erc-input-marker)
+ `(display ,erc-prompt-hidden)))
(add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 0 t))))
(defun erc-process-sentinel (cproc event)
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index a833a61456..16cfb15a5a 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -150,92 +150,6 @@ If START or END is negative, it counts from the end."
(setq i (1+ i) start (1+ start)))
res))))))
-;;;; Auth Source
-
-;; We want a unified interface to auth-source, but that depends on
-;; upstream providing a consistent experience. As of at least
-;;
-;; lisp/auth-source-pass.el: Support multiple hosts in search
-;; b09ee1406205e8b6298411b9a18c1cd26e201689 Fri Jul 2 2021
-;;
-;; auth-source-pass only returns singletons on success. But we want
-;; all possible matches. This provides some hacks to do that, but it
-;; depends on internal functions. We also need to pass lists of
-;; candidates for host, user, and port selectors, which aren't yet
-;; fully supported.
-;;
-
-(require 'auth-source)
-
-(declare-function auth-source-pass--get-attr
- "auth-source-pass" (key entry-data))
-(declare-function auth-source-pass--disambiguate
- "auth-source-pass" (host &optional user port))
-(declare-function auth-source-pass--find-match-unambiguous
- "auth-source-pass" (hostname user port))
-(declare-function auth-source-backend-parse-parameters
- "auth-source-pass" (entry backend))
-
-(defun erc-compat--auth-source-pass--couch (s)
- (lambda () (auth-source-pass--get-attr 'secret s)))
-
-(defun erc-compat--auth-source-pass--find-match (hosts ports users)
- "Return a plist of HOSTS, PORTS, USERS, and secret.
-This is not a drop-in for `auth-source-pass--find-match', which
-returns an alist."
- (unless (listp hosts) (setq hosts (list hosts)))
- (unless (listp users) (setq users (list users)))
- (unless (listp ports) (setq ports (list ports)))
- ;; Try combinations of Hosts x Users x Ports, filter out nonexistent
- (cl-loop for host in hosts
- for (h u p) = (auth-source-pass--disambiguate host)
- append
- (cl-loop for user in (or users (list u))
- append
- (cl-loop for port in (or ports (list p))
- for s = (auth-source-pass--find-match-unambiguous
- h user port)
- when s collect
- ;; Keep original host
- `(:host
- ,host
- ,@(and user (list :user user))
- ,@(and port (list :port port))
- :secret
- ,(erc-compat--auth-source-pass--couch s))))))
-
-(defun erc-compat--auth-source-pass--build-result (hosts ports users
- &optional max)
- "Multi-valued `auth-source-pass--build-result'."
- (unless max (setq max 1))
- (let ((entries (erc-compat--auth-source-pass--find-match hosts ports users))
- (count -1)
- entry
- out)
- (while (and (setq entry (pop entries)) (< (cl-incf count) max))
- (push entry out))
- out))
-
-(cl-defun erc-compat--auth-source-pass-search
- (&rest spec &key backend type host user port max &allow-other-keys)
- (cl-assert (or (null type) (eq type (oref backend type)))
- t "Invalid password-store search: %s %s")
- (cl-assert (and host (not (eq host t)))
- t "Invalid password-store search: %s %s")
- (erc-compat--auth-source-pass--build-result host port user max))
-
-;; Temporary until we decide whether to load compat by default
-
-;;;###autoload
-(defun erc-compat--auth-source-pass-backend-parse (entry)
- (when (eq entry 'password-store)
- (auth-source-backend-parse-parameters
- entry (auth-source-backend
- :source "."
- :type 'password-store
- :search-function #'erc-compat--auth-source-pass-search))))
-
-
(provide 'erc-compat)
;;; erc-compat.el ends here
diff --git a/lisp/erc/erc-join.el b/lisp/erc/erc-join.el
index b812dfc512..01dceffdde 100644
--- a/lisp/erc/erc-join.el
+++ b/lisp/erc/erc-join.el
@@ -175,8 +175,8 @@ Respects `erc-autojoin-domain-only'."
"Add the channel being joined to `erc-autojoin-channels-alist'."
(when-let* ((nick (car (erc-parse-user (erc-response.sender parsed))))
((erc-current-nick-p nick))
- (chnl (erc-response.contents parsed))
- (elem (or (and (erc-valid-local-channel-p chnl)
+ (chnl (car (erc-response.command-args parsed)))
+ (elem (or (and (erc--valid-local-channel-p chnl)
(regexp-quote erc-server-announced-name))
(erc-networks--id-symbol erc-networks--id)
(with-current-buffer (process-buffer proc)
@@ -195,7 +195,7 @@ Respects `erc-autojoin-domain-only'."
(when-let* ((nick (car (erc-parse-user (erc-response.sender parsed))))
((erc-current-nick-p nick))
(chnl (car (erc-response.command-args parsed)))
- (elem (or (and (erc-valid-local-channel-p chnl)
+ (elem (or (and (erc--valid-local-channel-p chnl)
(regexp-quote erc-server-announced-name))
(erc-networks--id-symbol erc-networks--id)
(with-current-buffer (process-buffer proc)
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index 5a97024ea0..0c9c2b41b2 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -740,7 +740,7 @@ MATCHER is used to find a corresponding network to a server
while
;; This relationship is quasi-permanent and transcends IRC connections
;; and Emacs sessions. As of early 2022, whether a user is
;; authenticated (logged in to an account) remains orthogonal to their
-;; network identity from a client's perspective. ERC must be equipped
+;; network identity from a client's perspective. ERC must be equipped
;; to adapt should this ever change.
;;
;; While a connection is normally associated with exactly one nick,
@@ -762,7 +762,7 @@ Here, \"presence\" refers to some local state representing
a persistent
existence on a network. The management of this state involves tracking
associated buffers and what they're displaying. Since a presence can
outlast physical connections and survive changes in back-end transports
-\(and even outlive Emacs sessions), its identity must remain resilient.
+\(and even outlive Emacs sessions), its identity must be resilient.
Essential to this notion of an enduring existence on a network is
ensuring recovery from the loss of a server buffer. Thus, any useful
@@ -792,18 +792,19 @@ set of connection parameters. See the constructor
(len 1))))
"A network presence identified by certain connection parameters.
Two identifiers are considered equivalent when their non-empty `parts'
-slots compare equal. Identifiers sharing a common prefix of `parts' are
-considered related. An identifier's canonical ID is determined by
-concatenating the shortest prefix (non-empty initial substring of
-`parts') unique among those of its relatives. For example, related
-presences [b a r d o] and [b a z a r] would have IDs b/a/r and b/a/z
-respectively. The separator is given by `erc-networks--id-sep'."
+slots compare equal. Related identifiers share a common prefix of
+`parts' taken from connection parameters (given or discovered). An
+identifier's unique `symbol', intended for display purposes, is created
+by concatenating the shortest common prefix among its relatives. For
+example, related presences [b a r d o] and [b a z a r] would have IDs
+b/a/r and b/a/z respectively. The separator is given by
+`erc-networks--id-sep'."
(parts nil :type sequence ; a vector of atoms
:documentation "Sequence of identifying components.")
(len 0 :type integer
:documentation "Length of active `parts' interval."))
-;; Please use this instead of `erc-networks--id-fixed-p'.
+;; For now, please use this instead of `erc-networks--id-fixed-p'.
(cl-defgeneric erc-networks--id-given (net-id)
"Return the preassigned identifier for a network presence, if any.
This may have come in the form of an :id arg to an \"entry-point\"
@@ -909,7 +910,7 @@ them with string separator `erc-networks--id-sep'."
(erc-networks--id-telescopic-parts nid))))
(defun erc-networks--id-telescopic-prefix-length (nid-a nid-b)
- "Return length of common initial prefix of NID-a and NID-B.
+ "Return length of common initial prefix of NID-A and NID-B.
Return nil when no such sequence exists (instead of zero)."
(when-let* ((a (erc-networks--id-telescopic-parts nid-a))
(b (erc-networks--id-telescopic-parts nid-b))
diff --git a/lisp/erc/erc-services.el b/lisp/erc/erc-services.el
index f042a52250..ca3eca5bdb 100644
--- a/lisp/erc/erc-services.el
+++ b/lisp/erc/erc-services.el
@@ -174,6 +174,18 @@ function `erc-nickserv-get-password'."
:version "28.1"
:type 'boolean)
+(defcustom erc-auth-source-parameters-services-function
+ #'erc-auth-source-determine-params-merge
+ "NickServ-specific filter for `auth-source-search'.
+Called with keyword parameters known to `auth-source-search' and
+relevant to authenticating to nickname services. In return, ERC expects
+a possibly modified set of parameters for querying auth-source and for
+narrowing the results. See info node `(erc) Connecting' for details."
+ :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
+ :type '(choice (const erc-auth-source-determine-params-merge)
+ (const nil)
+ function))
+
(defcustom erc-nickserv-passwords nil
"Passwords used when identifying to NickServ automatically.
`erc-prompt-for-nickserv-password' must be nil for these
@@ -436,8 +448,11 @@ it returns nil."
(ret (or (when erc-nickserv-passwords
(assoc-default nick
(cadr (assq esid erc-nickserv-passwords))))
- (when erc-use-auth-source-for-nickserv-password
- (erc--auth-source-search :user nick))
+ (when (and erc-use-auth-source-for-nickserv-password
+ erc-auth-source-parameters-services-function)
+ (apply #'erc--auth-source-search
+ (funcall erc-auth-source-parameters-services-function
+ :user nick)))
(when erc-prompt-for-nickserv-password
(read-passwd
(format "NickServ password for %s on %s (RET to cancel): "
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index f25b2f2305..e8ee7b3710 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -249,28 +249,6 @@ node `(auth) Top' and info node `(erc) Connecting'.")
:group 'erc
:type 'boolean)
-(defcustom erc-connect-auth-source-host 'server
- "Host \"type\" for querying auth-source when first connecting.
-This is for determining the \"server password\" argument of the IRC
-\"PASS\" command sent to the server. The entry points `erc' and
-`erc-tls' query auth-source for such a password when a :password
-argument isn't provided. Because ERC also interfaces with auth-source
-for other secrets, such as NickServ passwords and channel keys,
-additional ways of selecting entries are sometimes necessary. See info
-node `(auth) Top'.
-
-Note that there aren't any options for specifying a network, like
-Libera.Chat, or a network-specific server, such as foo.libera.chat,
-because such information isn't available until after initial
-introductions have completed (\"registration\" in IRC speak)."
- :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA
- :group 'erc
- :type '(choice (const :tag "Don't query auth-source" nil)
- (const :tag "Dialed host name or IP address" server)
- (const :tag "Prompt for a machine/host value" prompt)
- (const :tag "Session ID, if set, otherwise server" t)
- (string :tag "Literal value to use for :host")))
-
(defcustom erc-warn-about-blank-lines t
"Warn the user if they attempt to send a blank line."
:group 'erc
@@ -291,14 +269,25 @@ introductions have completed (\"registration\" in IRC
speak)."
"If non-nil, hide input prompt upon disconnecting.
To unhide, type something in the input area. Once revealed, a prompt
remains unhidden until the next disconnection. Channel prompts are
-unhidden upon rejoining. Query prompts remain hidden until user input
-is detected or a new message arrives from the target."
+unhidden upon rejoining. See `erc-unhide-query-prompt' for behavior
+concerning query prompts."
:package-version '(ERC . "5.4.1") ; FIXME increment on next ELPA release
:group 'erc-display
:type '(choice (const :tag "Always hide prompt" t)
- (const :tag "Never hide prompt" nil)
- (const :tag "Only hide target prompt" 'target)
- (const :tag "Only hide server prompt" 'server)))
+ (set (const server)
+ (const query)
+ (const channel))))
+
+(defcustom erc-unhide-query-prompt nil
+ "When non-nil, always reveal query prompts upon reconnecting.
+Otherwise, prompts in a connection's query buffers remain hidden until
+the user types in the input area or a new message arrives from the
+target."
+ :package-version '(ERC . "5.4.1")
+ :group 'erc-display
+ ;; Extensions may one day offer a way to discover whether a target
+ ;; is online. When that happens, this can be expanded accordingly.
+ :type 'boolean)
;; tunable GUI stuff
@@ -1424,14 +1413,23 @@ if ARG is omitted or nil.
(string "" :type string :documentation "Received name of target.")
(symbol nil :type symbol :documentation "Case-mapped name as symbol."))
+;; These should probably take on a `joined' field to track joinedness,
+;; which should be toggled by `erc-server-JOIN', `erc-server-PART',
+;; etc. Functions like `erc--current-buffer-joined-p' (bug#48598) may
+;; find it useful.
+
(cl-defstruct (erc--target-channel (:include erc--target)))
(cl-defstruct (erc--target-channel-local (:include erc--target-channel)))
+;; At some point, it may make sense to add a query type with an
+;; account field, which may help support reassociation across
+;; reconnects and nick changes (likely requires v3 extensions).
+
(defun erc--target-from-string (string)
"Construct an `erc--target' variant from STRING."
(funcall (if (erc-channel-p string)
- (if (erc-valid-local-channel-p string)
+ (if (erc--valid-local-channel-p string)
#'make-erc--target-channel-local
#'make-erc--target-channel)
#'make-erc--target)
@@ -2407,7 +2405,7 @@ Example usage:
(erc-tls :server \"irc.libera.chat\" :port 6697
:client-certificate
- '(\"/home/bandali/my-cert.key\"
+ \\='(\"/home/bandali/my-cert.key\"
\"/home/bandali/my-cert.crt\"))
When present, ID should be an opaque object for identifying the
@@ -3321,39 +3319,38 @@ For a list of user commands (/join /part, ...):
(defalias 'erc-cmd-H #'erc-cmd-HELP)
(put 'erc-cmd-HELP 'process-not-needed t)
-(defcustom erc-auth-source-parameters-function
- #'erc--auth-source-determine-params
- "A function providing args to pass to `auth-source-search'.
-This is called with no arguments and should return a plist of keyword
-args accepted by `auth-source-search'. The ordering of the pairs
-influences how results are filtered as does the ordering of the members
-of any composite pair values, when applicable. If necessary, the former
-takes priority over the latter. For example, if the function returns
-
- (:host (foo bar) :port (123 456) :require (:secret))
-
-the secret from an auth-source entry of host foo and port 456
-will be chosen over another of host bar and port 123. However,
-if the function returns
-
- (:port (123 456) :host (foo bar) :require (:secret))
-
-the opposite will be true. In both cases, two entries with the same
-host but different ports would see the one with port 123 being selected.
-Much the same would happen for entries sharing only a port: the one with
-host foo would win.
-
-Some auth-source back ends may not be compatible (netrc and pass are
-currently supported)."
- :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA
+(defcustom erc-auth-source-parameters-server-function
+ #'erc-auth-source-determine-params-merge
+ "Server-password filter for `auth-source-search'.
+Called with keyword parameters known to `auth-source-search' and
+relevant to an opening \"PASS\" command, if any. In return, ERC expects
+an optionally modified set of parameters to use both for the auth-source
+query and for narrowing its results. A value of nil tells ERC to omit
+the \"PASS\" command completely. An explicit `:password' argument to
+entry-point commands `erc' and `erc-tls' also inhibits look-up. See
+info node `(erc) Connecting' for details."
+ :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
:group 'erc
- :type 'function)
+ :type '(choice (const erc-auth-source-determine-params-merge)
+ (const nil)
+ function))
+
+(defcustom erc-auth-source-parameters-join-function
+ #'erc-auth-source-determine-params-merge
+ "Channel-join filter for `auth-source-search'.
+Called with keyword parameters known to `auth-source-search' and
+relevant to joining a password-protected channel. In return, ERC
+expects an optionally modified set of parameters to use both for the
+auth-source query and for narrowing its results. A value of nil tells
+ERC to forgo consulting auth-source for channel keys. For more
+information, see info node `(erc) Connecting'."
+ :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
+ :group 'erc
+ :type '(choice (const erc-auth-source-determine-params-merge)
+ (const nil)
+ function))
-(defun erc--auth-source-determine-params ()
- "Return a plist of default args to pass to `auth-source-search'.
-Favor a network ID over an announced server unless `erc--target' is a
-local channel. Treat the dialed server address as a fallback for the
-announced name in both cases."
+(defun erc--auth-source-determine-params-defaults ()
(let* ((net (and-let* ((esid (erc-networks--id-symbol erc-networks--id))
((symbol-name esid)))))
(localp (and erc--target (erc--target-channel-local-p erc--target)))
@@ -3366,44 +3363,47 @@ announced name in both cases."
erc-session-port)) ; or nil
(t erc-session-port))
"irc")))
- (list :host (delq nil hosts)
- :port (delq nil ports)
- :require '(:secret))))
-
-(declare-function erc-compat--auth-source-pass-backend-parse
- "erc-compat" (entry))
-
-(defun erc--auth-source-search (&rest plist)
+ (list (cons :host (delq nil hosts))
+ (cons :port (delq nil ports))
+ (cons :require '(:secret)))))
+
+(defun erc-auth-source-determine-params-merge (&rest plist)
+ "Return a plist of merged keyword args to pass to `auth-source-search'.
+Combine items in PLIST with others derived from the current connection
+context, but prioritize the former. For keys not present in PLIST,
+favor a network ID over an announced server unless `erc--target' is a
+local channel. And treat the dialed server address as a fallback for
+the announced name in both cases."
+ (let ((defaults (erc--auth-source-determine-params-defaults)))
+ `(,@(cl-loop for (key value) on plist by #'cddr
+ for default = (assq key defaults)
+ do (when default (setq defaults (delq default defaults)))
+ append `(,key ,(delete-dups
+ `(,@(if (consp value) value (list value))
+ ,@(cdr default)))))
+ ,@(cl-loop for (k . v) in defaults append (list k v)))))
+
+(defun erc--auth-source-search (&rest defaults)
"Ask auth-source for a secret and return it if found.
-Favor overrides in PLIST, if any. Otherwise, use whatever's present in
-the list returned by `erc-auth-source-parameters-function'. Return a
-string if found or nil otherwise."
- (let* ((auth-source-backend-parser-functions
- (if (memq 'password-store auth-sources)
- (cons #'erc-compat--auth-source-pass-backend-parse
- auth-source-backend-parser-functions)
- auth-source-backend-parser-functions))
- (defaults (funcall erc-auth-source-parameters-function))
- priority
- (test (lambda (a b)
- (catch 'done
- (dolist (key priority)
- (let* ((d (plist-get defaults key))
- (default-value (if (listp d) d (list d)))
- ;; featurep 'seq via auth-source > json > map
- (p (seq-position default-value (plist-get a key)))
- (q (seq-position default-value (plist-get b key))))
- (unless (eql p q)
- (throw 'done (when p (or (not q) (< p q)))))))))))
- (cl-loop for (key value) on defaults by #'cddr
- when value unless (plist-get plist key)
- do (setq plist (plist-put plist key value)))
- (let ((keys (nreverse (map-keys defaults))))
- (dolist (key (map-keys plist))
- (cl-pushnew key keys))
- (setq priority (nreverse keys)))
- (unless (plist-get plist :max) ; from `auth-source-netrc-parse'
- (setq plist (plist-put plist :max 5000)))
+Use DEFAULTS as arguments for querying auth-source and as a guide for
+narrowing the results. Return a string if found or nil otherwise."
+ (when-let*
+ ((priority (map-keys defaults))
+ (test (lambda (a b)
+ (catch 'done
+ (dolist (key priority)
+ (let* ((d (plist-get defaults key))
+ (defval (if (listp d) d (list d)))
+ ;; featurep 'seq via auth-source > json > map
+ (p (seq-position defval (plist-get a key)))
+ (q (seq-position defval (plist-get b key))))
+ (unless (eql p q)
+ (throw 'done (when p (or (not q) (< p q))))))))))
+ (plist (copy-sequence defaults)))
+ (unless (plist-get plist :max)
+ (setq plist (plist-put plist :max 5000))) ; `auth-source-netrc-parse'
+ (unless (plist-get defaults :require)
+ (setq plist (plist-put plist :require '(:secret))))
(when-let* ((sorted (sort (apply #'auth-source-search plist) test))
(secret (plist-get (car sorted) :secret)))
(if (functionp secret) (funcall secret) secret))))
@@ -3411,16 +3411,18 @@ string if found or nil otherwise."
(defun erc-server-join-channel (server channel &optional secret)
"Join CHANNEL, optionally with SECRET.
Without SECRET, consult auth source, using SERVER if non-nil."
- (unless secret
+ (unless (or secret (not erc-auth-source-parameters-join-function))
(unless server
- (when (and erc-server-announced-name (erc-valid-local-channel-p channel))
+ (when (and erc-server-announced-name
+ (erc--valid-local-channel-p channel))
(setq server erc-server-announced-name)))
- (let ((args `(,@(when server (list :host server)) :user channel)))
+ (let ((args (apply erc-auth-source-parameters-join-function
+ `(,@(and server (list :host server)) :user channel))))
(setq secret (apply #'erc--auth-source-search args))))
(erc-log (format "cmd: JOIN: %s" channel))
(erc-server-send (concat "JOIN " channel (when secret (concat " " secret)))))
-(defun erc-valid-local-channel-p (channel)
+(defun erc--valid-local-channel-p (channel)
"Non-nil when channel is server-local on a network that allows them."
(and-let* (((eq ?& (aref channel 0)))
(chan-types (erc--get-isupport-entry 'CHANTYPES 'single))
@@ -4955,7 +4957,14 @@ Set user modes and run `erc-after-connect' hook."
(erc-update-mode-line)
(erc-set-initial-user-mode nick buffer)
(erc-server-setup-periodical-ping buffer)
- (run-hook-with-args 'erc-after-connect server nick)))))
+ (run-hook-with-args 'erc-after-connect server nick))))
+
+ (when erc-unhide-query-prompt
+ (erc-with-all-buffers-of-server proc
+ nil ; FIXME use `erc--target' after bug#48598
+ (when (and (erc-default-target)
+ (not (erc-channel-p (car erc-default-recipients))))
+ (erc--unhide-prompt)))))
(defun erc-set-initial-user-mode (nick buffer)
"If `erc-user-mode' is non-nil for NICK, set the user modes.
@@ -6416,7 +6425,7 @@ Sets the buffer local variables:
erc-session-port (or port erc-default-port)
erc-session-user-full-name (erc-compute-full-name name)
erc-session-username (erc-compute-user user)
- erc-session-password (erc-compute-server-password passwd nick))
+ erc-session-password (erc--compute-server-password passwd nick))
(erc-set-current-nick (erc-compute-nick nick)))
(defun erc-compute-server (&optional server)
@@ -6453,19 +6462,15 @@ non-nil value is found.
(getenv "IRCNICK")
(user-login-name)))
-(defun erc-compute-server-password (password nick)
- "Determine initial PASSWORD value for IRC PASS command.
-Use the value of `erc-connect-auth-source-host' to determine the
-machine/host query param. Use NICK for the user/login query param."
+(defun erc--compute-server-password (password nick)
+ "Maybe provide a PASSWORD argument for the IRC \"PASS\" command.
+Use NICK for the user field when querying auth-source. Defer to
+`erc-auth-source-parameters-server-function' for the host param."
(or password
- (when erc-connect-auth-source-host
- (let* ((host (pcase erc-connect-auth-source-host
- ('server erc-session-server)
- ((and (pred stringp) v) v)
- ('prompt (read-string "Auth-source host: "
- nil t (list nil)))))
- (args `(,@(when host (list :host host)) :user ,nick)))
- (apply #'erc--auth-source-search args)))))
+ (and erc-auth-source-parameters-server-function
+ (apply #'erc--auth-source-search
+ (funcall erc-auth-source-parameters-server-function
+ :user nick)))))
(defun erc-compute-full-name (&optional full-name)
"Return user's full name.
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/proxy-subprocess.el
b/test/lisp/erc/erc-d/erc-d-self-resources/proxy-subprocess.el
deleted file mode 100644
index 6e4624050a..0000000000
--- a/test/lisp/erc/erc-d/erc-d-self-resources/proxy-subprocess.el
+++ /dev/null
@@ -1,26 +0,0 @@
-;;; proxy-subprocess.el --- Example setup file for erc-d
-;;; Commentary:
-;;; Code:
-
-(defvar erc-d-spec-vars)
-
-(setq erc-d-spec-vars
-
- (list
- (cons 'fqdn (lambda (helper)
- (let ((name (funcall helper :dialog-name)))
- (funcall helper :set
- (if (eq name 'proxy-foonet)
- "irc.foo.net"
- "irc.bar.net")))))
-
- (cons 'net (lambda (helper)
- (let ((name (funcall helper :dialog-name)))
- (funcall helper :set
- (if (eq name 'proxy-foonet)
- "FooNet"
- "BarNet")))))
-
- (cons 'network '(group (+ alpha)))))
-
-;;; proxy-subprocess.el ends here
diff --git a/test/lisp/erc/erc-join-tests.el b/test/lisp/erc/erc-join-tests.el
index e9c432b4a2..2eb20ffd8d 100644
--- a/test/lisp/erc/erc-join-tests.el
+++ b/test/lisp/erc/erc-join-tests.el
@@ -30,7 +30,7 @@
(let (calls
common
- erc-kill-server-hook)
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
(cl-letf (((symbol-function 'erc-server-send)
(lambda (line) (push line calls))))
@@ -78,7 +78,7 @@
(let (calls
common
- erc-kill-server-hook
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook
(erc-autojoin-timing 'ident)
(erc-autojoin-delay 0.05))
@@ -127,7 +127,7 @@
(let (calls
common
- erc-kill-server-hook
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook
(erc-autojoin-timing 'ident))
(cl-letf (((symbol-function 'erc-server-send)
@@ -157,9 +157,10 @@
(funcall common))
(should (equal (pop calls) "JOIN #chan"))))))
-(defun erc-join-tests--autojoin-add--common (setup)
+(defun erc-join-tests--autojoin-add--common (setup &optional fwd)
(let (calls
- erc-autojoin-channels-alist)
+ erc-autojoin-channels-alist
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
(cl-letf (((symbol-function 'erc-handle-parsed-server-response)
(lambda (_p m) (push m calls))))
@@ -178,14 +179,16 @@
(ert-info ("Add #chan")
(erc-parse-server-response erc-server-process
- ":tester!~i@c.u JOIN #chan")
+ (concat ":tester!~i@c.u JOIN #chan"
+ (and fwd " * :Tes Ter")))
(should calls)
(erc-autojoin-add erc-server-process (pop calls))
(should (equal erc-autojoin-channels-alist '((FooNet "#chan")))))
(ert-info ("More recently joined chans are prepended")
- (erc-parse-server-response erc-server-process
- ":tester!~i@c.u JOIN #spam")
+ (erc-parse-server-response
+ erc-server-process ; with account username
+ (concat ":tester!~i@c.u JOIN #spam" (and fwd " tester :Tes Ter")))
(should calls)
(erc-autojoin-add erc-server-process (pop calls))
(should (equal erc-autojoin-channels-alist
@@ -193,7 +196,8 @@
(ert-info ("Duplicates skipped")
(erc-parse-server-response erc-server-process
- ":tester!~i@c.u JOIN #chan")
+ (concat ":tester!~i@c.u JOIN #chan"
+ (and fwd " * :Tes Ter")))
(should calls)
(erc-autojoin-add erc-server-process (pop calls))
(should (equal erc-autojoin-channels-alist
@@ -201,7 +205,8 @@
(ert-info ("Server used for local channel")
(erc-parse-server-response erc-server-process
- ":tester!~i@c.u JOIN &local")
+ (concat ":tester!~i@c.u JOIN &local"
+ (and fwd " * :Tes Ter")))
(should calls)
(erc-autojoin-add erc-server-process (pop calls))
(should (equal erc-autojoin-channels-alist
@@ -213,6 +218,12 @@
(lambda () (setq erc-network 'FooNet
erc-networks--id (erc-networks--id-create nil)))))
+(ert-deftest erc-autojoin-add--network-extended-syntax ()
+ (erc-join-tests--autojoin-add--common
+ (lambda () (setq erc-network 'FooNet
+ erc-networks--id (erc-networks--id-create nil)))
+ 'forward-compatible))
+
(ert-deftest erc-autojoin-add--network-id ()
(erc-join-tests--autojoin-add--common
(lambda () (setq erc-network 'invalid
@@ -220,7 +231,8 @@
(ert-deftest erc-autojoin-add--server ()
(let (calls
- erc-autojoin-channels-alist)
+ erc-autojoin-channels-alist
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
(cl-letf (((symbol-function 'erc-handle-parsed-server-response)
(lambda (_p m) (push m calls))))
@@ -245,7 +257,8 @@
(defun erc-join-tests--autojoin-remove--common (setup)
(let (calls
- erc-autojoin-channels-alist)
+ erc-autojoin-channels-alist
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
(cl-letf (((symbol-function 'erc-handle-parsed-server-response)
(lambda (_p m) (push m calls))))
@@ -307,7 +320,8 @@
(ert-deftest erc-autojoin-remove--server ()
(let (calls
- erc-autojoin-channels-alist)
+ erc-autojoin-channels-alist
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
(cl-letf (((symbol-function 'erc-handle-parsed-server-response)
(lambda (_p m) (push m calls))))
diff --git a/test/lisp/erc/erc-scenarios-common.el
b/test/lisp/erc/erc-scenarios-common.el
deleted file mode 100644
index 9d81c0ee74..0000000000
--- a/test/lisp/erc/erc-scenarios-common.el
+++ /dev/null
@@ -1,152 +0,0 @@
-;;; erc-scenarios-common.el --- common helpers for ERC scenarios -*-
lexical-binding: t -*-
-
-;; Copyright (C) 2021 Free Software Foundation, Inc.
-;;
-;; This file is part of GNU Emacs.
-;;
-;; 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
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This file should not contain any test cases.
-
-(require 'ert-x) ; cl-lib
-
-(eval-and-compile (let ((dir (getenv "EMACS_TEST_DIRECTORY")))
- (when dir
- (load (concat dir "/lisp/erc/erc-d/erc-d-t") nil t)
- (load (concat dir "/lisp/erc/erc-d/erc-d") nil t))))
-(require 'erc-d)
-(require 'erc-d-t)
-(require 'erc-backend)
-
-(defvar erc-scenarios-common--resources-dir
- (expand-file-name (concat (ert-resource-directory)
- "../erc-scenarios-resources/")))
-
-;; Because teardown is already inhibited when running interactively,
-;; which prevents subsequent tests from succeeding, we might as well
-;; treat inspection as the goal.
-(unless noninteractive
- (setq erc-server-auto-reconnect nil))
-
-(defvar erc-scenarios-common-dialog nil)
-(defvar erc-scenarios-common-extra-teardown nil)
-
-(defun erc-scenarios-common--add-silence ()
- (advice-add #'erc-login :around #'erc-d-t-silence-around)
- (advice-add #'erc-handle-login :around #'erc-d-t-silence-around)
- (advice-add #'erc-server-connect :around #'erc-d-t-silence-around))
-
-(defun erc-scenarios-common--remove-silence ()
- (advice-remove #'erc-login #'erc-d-t-silence-around)
- (advice-remove #'erc-handle-login #'erc-d-t-silence-around)
- (advice-remove #'erc-server-connect #'erc-d-t-silence-around))
-
-(defun erc-scenarios-common--print-trace ()
- (when (and (boundp 'trace-buffer) (get-buffer trace-buffer))
- (with-current-buffer trace-buffer
- (message "%S" (buffer-string))
- (kill-buffer))))
-
-(defun erc-scenarios-common--make-bindings (bindings)
- `((erc-d-u-canned-dialog-dir (expand-file-name
- (or erc-scenarios-common-dialog
- (cadr (assq 'erc-scenarios-common-dialog
- ',bindings)))
- erc-scenarios-common--resources-dir))
- (erc-d-spec-vars `(,@erc-d-spec-vars
- (quit . ,(erc-quit/part-reason-default))
- (erc-version . ,erc-version)))
- (erc-modules (copy-sequence erc-modules))
- (inhibit-interaction t)
- (auth-source-do-cache nil)
- (erc-autojoin-channels-alist nil)
- (erc-server-auto-reconnect nil)
- ,@bindings))
-
-(defmacro erc-scenarios-common-with-cleanup (bindings &rest body)
- "Provide boilerplate cleanup tasks after calling BODY with BINDINGS.
-
-If an `erc-d' process exists, wait for it to start before running BODY.
-If `erc-autojoin-mode' mode is bound, restore it during cleanup if
-disabled by BODY. Other defaults common to these test cases are added
-below and can be overridden, except when wanting the \"real\" default
-value, which must be looked up or captured outside of the calling form.
-
-Dialog resource directories are located by expanding the variable
-`erc-scenarios-common-dialog' or its value in BINDINGS."
- (declare (indent 1))
-
- (let* ((orig-autojoin-mode (make-symbol "orig-autojoin-mode"))
- (combind `((,orig-autojoin-mode (bound-and-true-p erc-autojoin-mode))
- ,@(erc-scenarios-common--make-bindings bindings))))
-
- `(erc-d-t-with-cleanup (,@combind)
-
- (ert-info ("Restore autojoin, etc., kill ERC buffers")
- (dolist (buf (buffer-list))
- (when-let ((erc-d-u--process-buffer)
- (proc (get-buffer-process buf)))
- (erc-d-t-wait-for 5 "Dumb server dies on its own"
- (not (process-live-p proc)))))
-
- (erc-scenarios-common--remove-silence)
-
- (when erc-scenarios-common-extra-teardown
- (ert-info ("Running extra teardown")
- (funcall erc-scenarios-common-extra-teardown)))
-
- (when (and (boundp 'erc-autojoin-mode)
- (not (eq erc-autojoin-mode ,orig-autojoin-mode)))
- (erc-autojoin-mode (if ,orig-autojoin-mode +1 -1)))
-
- (when noninteractive
- (erc-scenarios-common--print-trace)
- (erc-d-t-kill-related-buffers)))
-
- (erc-scenarios-common--add-silence)
-
- (ert-info ("Wait for dumb server")
- (dolist (buf (buffer-list))
- (with-current-buffer buf
- (when erc-d-u--process-buffer
- (erc-d-t-search-for 3 "Starting")))))
-
- (ert-info ("Activate erc-debug-irc-protocol")
- (unless (and noninteractive (not erc-debug-irc-protocol))
- (erc-toggle-debug-irc-protocol)))
-
- ,@body)))
-
-(defun erc-scenarios-common-assert-initial-buf-name (id port)
- ;; Assert no limbo period when explicit ID given
- (should (string= (if id
- (symbol-name id)
- (format "127.0.0.1:%d" port))
- (buffer-name))))
-
-(defun erc-scenarios-common-buflist (prefix)
- "Return list of buffers with names sharing PREFIX."
- (let (case-fold-search)
- (erc-networks--id-sort-buffers
- (delq nil
- (mapcar (lambda (b)
- (when (string-prefix-p prefix (buffer-name b)) b))
- (buffer-list))))))
-
-(provide 'erc-scenarios-common)
-
-;;; erc-scenarios-common.el ends here
diff --git a/test/lisp/erc/erc-scenarios.el b/test/lisp/erc/erc-scenarios.el
deleted file mode 100644
index d206e4835c..0000000000
--- a/test/lisp/erc/erc-scenarios.el
+++ /dev/null
@@ -1,2312 +0,0 @@
-;;; erc-scenarios.el --- user test cases for ERC -*- lexical-binding: t -*-
-
-;; Copyright (C) 2021 Free Software Foundation, Inc.
-;;
-;; This file is part of GNU Emacs.
-;;
-;; 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
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; These are e2e-ish test cases primarily intended to assert core,
-;; fundamental behavior expected of any modern IRC client. Tests may
-;; also simulate specific scenarios drawn from bug reports. Incoming
-;; messages are provided by playback scripts resembling I/O logs. In
-;; place of time stamps, they have time deltas, which are used to
-;; govern the test server in a fashion reminiscent of music rolls (or
-;; the script(1) UNIX program). These scripts can be found in the
-;; accompanying erc-scenarios-resources directory.
-;;
-;; Isolation:
-;;
-;; The set of enabled modules is shared among all tests. The function
-;; `erc-update-modules' activates them (as minor modes), but it never
-;; deactivates them. So there's no going back, and let-binding
-;; `erc-modules' is useless. The safest route is therefore to (1)
-;; assume the set of default modules is already activated or will be
-;; over the course of the test session and (2) let-bind relevant user
-;; options as needed. For example, to limit the damage of
-;; `erc-autojoin-channels-alist' to a given test, assume the
-;; `erc-join' library has already been loaded or will be on the next
-;; call to `erc-open'. And then simply let-bind
-;; `erc-autojoin-channels-alist' for the duration of the test.
-;;
-;; Playing nice:
-;;
-;; Right now, these tests all rely on an ugly fixture macro named
-;; `erc-scenarios-common-with-cleanup', which is defined in the
-;; companion file erc-scenarios-common.el. It helps restore (but not
-;; really prepare) the environment by destroying any stray processes
-;; or buffers named in the first argument, a `let*'-style VAR-LIST.
-;; Relying on such a macro is unfortunate because in many ways it
-;; actually hampers readability by favoring magic over verbosity. But
-;; without it (or something similar), any failing test would cause all
-;; subsequent tests in this file to fail in a cascading manner (making
-;; all but the first backtrace useless).
-;;
-;; Misc:
-;;
-;; Note that in the following examples, nicknames Alice and Bob are
-;; always associated with the fake network FooNet, while nicks Joe and
-;; Mike are always on BarNet.
-;;
-
-;;; Code:
-(require 'ert-x) ; cl-lib
-
-(eval-and-compile
- (let ((dir (getenv "EMACS_TEST_DIRECTORY")))
- (when dir (load (concat dir "/lisp/erc/erc-scenarios-common") nil t))))
-
-(require 'erc-d)
-(require 'erc-scenarios-common)
-(require 'erc)
-(eval-when-compile (require 'erc-services))
-
-(declare-function erc-network-name "erc-networks")
-(declare-function erc-network "erc-networks")
-(defvar erc-autojoin-channels-alist)
-(defvar erc-network)
-
-;; Two networks, same channel name, no confusion (no bouncer). Some
-;; of this draws from bug#47522 "foil-in-server-buf". It shows that
-;; disambiguation-related changes added for bug#48598 are not specific
-;; to bouncers.
-
-(defun erc-scenarios-common--base-association-multi-net (second-join)
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/association/multi-net")
- (erc-server-flood-penalty 0.1)
- (erc-d-linger-secs 1)
- (dumb-server-foonet-buffer (get-buffer-create "*server-foonet*"))
- (dumb-server-barnet-buffer (get-buffer-create "*server-barnet*"))
- (dumb-server-foonet (erc-d-run "localhost" t "server-foonet" 'foonet))
- (dumb-server-barnet (erc-d-run "localhost" t "server-barnet" 'barnet))
- (expect (erc-d-t-make-expecter)))
-
- (ert-info ("Connect to foonet, join #chan")
- (with-current-buffer
- (erc :server "127.0.0.1"
- :port (process-contact dumb-server-foonet :service)
- :nick "tester"
- :password "changeme"
- :full-name "tester")
- (funcall expect 3 "debug mode")
- (erc-cmd-JOIN "#chan")))
-
- (erc-d-t-wait-for 2 (get-buffer "#chan"))
-
- (ert-info ("Connect to barnet, join #chan")
- (with-current-buffer
- (erc :server "127.0.0.1"
- :port (process-contact dumb-server-barnet :service)
- :nick "tester"
- :password "changeme"
- :full-name "tester")
- (funcall expect 1 "debug mode")))
-
- (funcall second-join)
-
- (erc-d-t-wait-for 3 (get-buffer "#chan@barnet"))
-
- (erc-d-t-wait-for 2 "Buf #chan now #chan@foonet"
- (and (get-buffer "#chan@foonet") (not (get-buffer "#chan"))))
-
- (ert-info ("All #chan@foonet output consumed")
- (with-current-buffer "#chan@foonet"
- (funcall expect 3 "bob")
- (funcall expect 3 "was created on")
- (funcall expect 3 "prosperous")))
-
- (ert-info ("All #chan@barnet output consumed")
- (with-current-buffer "#chan@barnet"
- (funcall expect 3 "mike")
- (funcall expect 3 "was created on")
- (funcall expect 3 "ingenuous")))))
-
-(ert-deftest erc-scenarios-base-association-multi-net--baseline ()
- (erc-scenarios-common--base-association-multi-net
- (lambda () (with-current-buffer "barnet" (erc-cmd-JOIN "#chan")))))
-
-;; The /join command only targets the current buffer's process. This
-;; recasts scenario bug#48598 "ambiguous-join" (which was based on
-;; bug#47522) to show that issuing superfluous /join commands
-;; (apparently fairly common) is benign.
-
-(ert-deftest erc-scenarios-base-association-multi-net--ambiguous-join ()
- (erc-scenarios-common--base-association-multi-net
- (lambda ()
- (ert-info ("Nonsensical JOIN attempts silently dropped.")
- (with-current-buffer "foonet" (erc-cmd-JOIN "#chan"))
- (sit-for 0.1)
- (with-current-buffer "#chan" (erc-cmd-JOIN "#chan"))
- (sit-for 0.1)
- (erc-d-t-wait-for 2 (get-buffer "#chan"))
- (erc-d-t-wait-for 1 "Only one #chan buffer exists"
- (should (equal (erc-scenarios-common-buflist "#chan")
- (list (get-buffer "#chan")))))
- (with-current-buffer "*server-barnet*"
- (erc-d-t-absent-for 0.1 "JOIN"))
- (with-current-buffer "barnet" (erc-cmd-JOIN "#chan"))))))
-
-;; One network, two simultaneous connections, no IDs.
-;; Reassociates on reconnect with and without server buffer.
-
-(defun erc-scenarios-common--base-association-same-network (after)
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/association/same-network")
- (dumb-server (erc-d-run "localhost" t 'tester 'chester 'tester-again))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-flood-penalty 0.5)
- (erc-server-flood-margin 30))
-
- (ert-info ("Connect to foonet with nick tester")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester")
- (erc-scenarios-common-assert-initial-buf-name nil port)
- (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
-
- (ert-info ("Connect to foonet with nick chester")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "chester"
- :password "changeme"
- :full-name "chester")
- (erc-scenarios-common-assert-initial-buf-name nil port)))
-
- (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
- (not (erc-scenarios-common-buflist "127.0.0.1")))
-
- (with-current-buffer "foonet/tester"
- (funcall expect 3 "debug mode")
- (erc-cmd-JOIN "#chan"))
-
- (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
- (with-current-buffer "foonet/chester" (funcall expect 3 "debug mode"))
- (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
-
- (ert-info ("Nick tester sees other nick chester in channel")
- (with-current-buffer "#chan@foonet/tester"
- (funcall expect 5 "chester")
- (funcall expect 5 "find the forester")
- (erc-cmd-QUIT "")))
-
- (ert-info ("Nick chester sees other nick tester in same channel")
- (with-current-buffer "#chan@foonet/chester"
- (funcall expect 5 "tester")
- (funcall expect 5 "find the forester")))
-
- (funcall after expect)))
-
-(ert-deftest erc-scenarios-base-association-same-network--reconnect-one ()
- (erc-scenarios-common--base-association-same-network
- (lambda (expect)
-
- (ert-info ("Connection tester reconnects")
- (with-current-buffer "foonet/tester"
- (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
- (funcall expect 10 "*** ERC finished")
- (erc-cmd-RECONNECT)
- (funcall expect 5 "debug mode")))
-
- (ert-info ("Reassociated to same channel")
- (with-current-buffer "#chan@foonet/tester"
- (funcall expect 5 "chester")
- (funcall expect 5 "welcome again")
- (erc-cmd-QUIT "")))
-
- (with-current-buffer "#chan@foonet/chester"
- (funcall expect 5 "tester")
- (funcall expect 5 "welcome again")
- (funcall expect 5 "welcome again")
- (erc-cmd-QUIT "")))))
-
-(ert-deftest erc-scenarios-base-association-same-network--new-buffer ()
- (erc-scenarios-common--base-association-same-network
- (lambda (expect)
-
- (ert-info ("Tester kills buffer and connects from scratch")
-
- (let (port)
- (with-current-buffer "foonet/tester"
- (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
- (funcall expect 10 "*** ERC finished")
- (setq port erc-session-port)
- (kill-buffer))
-
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester")
-
- (erc-d-t-wait-for 5 (eq erc-network 'foonet)))))
-
- (with-current-buffer "foonet/tester" (funcall expect 3 "debug mode"))
-
- (ert-info ("Reassociated to same channel")
- (with-current-buffer "#chan@foonet/tester"
- (funcall expect 5 "chester")
- (funcall expect 5 "welcome again")
- (erc-cmd-QUIT "")))
-
- (with-current-buffer "#chan@foonet/chester"
- (funcall expect 5 "tester")
- (funcall expect 5 "welcome again")
- (funcall expect 5 "welcome again")
- (erc-cmd-QUIT "")))))
-
-;; XXX this is okay, but we also need to check that target buffers are
-;; already associated with a new process *before* a JOIN is sent by a
-;; server's playback burst. This doesn't do that.
-;;
-;; This *does* check that superfluous JOINs sent by the autojoin
-;; module are harmless when they're not acked (superfluous because the
-;; bouncer/server intitates the JOIN).
-
-(defun erc-scenarios-common--join-network-id (foo-reconnector foo-id bar-id)
- "Ensure channels rejoined by erc-join.el DTRT.
-Originally from scenario clash-of-chans/autojoin as described in
-Bug#48598: 28.0.50; buffer-naming collisions involving bouncers in ERC."
- (erc-scenarios-common-with-cleanup
- ((chan-buf-foo (format "#chan@%s" (or foo-id "foonet")))
- (chan-buf-bar (format "#chan@%s" (or bar-id "barnet")))
- (erc-scenarios-common-dialog "join/network-id")
- (erc-d-t-cleanup-sleep-secs 1)
- (erc-server-flood-penalty 0.5)
- (dumb-server (erc-d-run "localhost" t 'foonet 'barnet 'foonet-again))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- erc-server-buffer-foo erc-server-process-foo
- erc-server-buffer-bar erc-server-process-bar)
-
- (should (memq 'autojoin erc-modules))
-
- (ert-info ("Connect to foonet")
- (with-current-buffer
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"
- :id foo-id))
- (setq erc-server-process-foo erc-server-process)
- (erc-scenarios-common-assert-initial-buf-name foo-id port)
- (erc-d-t-wait-for 1 (eq (erc-network) 'foonet))
- (funcall expect 5 "foonet")))
-
- (ert-info ("Join #chan, find sentinel, quit")
- (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
- (funcall expect 5 "vile thing")
- (erc-cmd-QUIT "")))
-
- (erc-d-t-wait-for 2 "Foonet connection deceased"
- (not (erc-server-process-alive erc-server-buffer-foo)))
-
- (should (equal erc-autojoin-channels-alist
- (if foo-id '((oofnet "#chan")) '((foonet "#chan")))))
-
- (ert-info ("Connect to barnet")
- (with-current-buffer
- (setq erc-server-buffer-bar (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "barnet:changeme"
- :full-name "tester"
- :id bar-id))
- (setq erc-server-process-bar erc-server-process)
- (erc-d-t-wait-for 5 (eq erc-network 'barnet))
- (should (string= (buffer-name) (if bar-id "rabnet" "barnet")))))
-
- (ert-info ("Server buffers are unique, no stray IP-based names")
- (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
- (should-not (erc-scenarios-common-buflist "127.0.0.1")))
-
- (ert-info ("Only one #chan buffer exists")
- (should (equal (list (get-buffer "#chan"))
- (erc-scenarios-common-buflist "#chan"))))
-
- (ert-info ("#chan is not auto-joined")
- (with-current-buffer "#chan"
- (erc-d-t-absent-for 0.1 "<joe>")
- (should-not (process-live-p erc-server-process))
- (erc-d-t-ensure-for 0.1 "server buffer remains foonet"
- (eq erc-server-process erc-server-process-foo))))
-
- (with-current-buffer erc-server-buffer-bar
- (erc-cmd-JOIN "#chan")
- (erc-d-t-wait-for 3 (get-buffer chan-buf-foo))
- (erc-d-t-wait-for 3 (get-buffer chan-buf-bar))
- (with-current-buffer chan-buf-bar
- (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-bar))
- (funcall expect 5 "marry her instantly")))
-
- (ert-info ("Reconnect to foonet")
- (with-current-buffer (setq erc-server-buffer-foo
- (funcall foo-reconnector))
- (should (member (if foo-id '(oofnet "#chan") '(foonet "#chan"))
- erc-autojoin-channels-alist))
- (erc-d-t-wait-for 3 (erc-server-process-alive))
- (setq erc-server-process-foo erc-server-process)
- (erc-d-t-wait-for 2 (eq erc-network 'foonet))
- (should (string= (buffer-name) (if foo-id "oofnet" "foonet")))
- (funcall expect 5 "foonet")))
-
- (ert-info ("#chan@foonet is clean, no cross-contamination")
- (with-current-buffer chan-buf-foo
- (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-foo))
- (funcall expect 3 "<bob>")
- (erc-d-t-absent-for 0.1 "<joe>")
- (while (accept-process-output erc-server-process-foo))
- (funcall expect 3 "not given me")))
-
- (ert-info ("All #chan@barnet output received")
- (with-current-buffer chan-buf-bar
- (while (accept-process-output erc-server-process-bar))
- (funcall expect 3 "hath an uncle here")))))
-
-(ert-deftest erc-scenarios-join-network-id--cmd-reconnect ()
- (let ((connect (lambda ()
- (with-current-buffer "foonet"
- (erc-cmd-RECONNECT)
- (should (eq (current-buffer)
- (process-buffer erc-server-process)))
- (current-buffer)))))
- (erc-scenarios-common--join-network-id connect nil nil)))
-
-(ert-deftest erc-scenarios-join-network-id--cmd-reconnect-id ()
- (let ((connect (lambda ()
- (with-current-buffer "oofnet"
- (erc-cmd-RECONNECT)
- (should (eq (current-buffer)
- (process-buffer erc-server-process)))
- (current-buffer)))))
- (erc-scenarios-common--join-network-id connect 'oofnet nil)))
-
-(ert-deftest erc-scenarios-join-network-id--cmd-reconnect-ids ()
- (let ((connect (lambda ()
- (with-current-buffer "oofnet"
- (erc-cmd-RECONNECT)
- (should (eq (current-buffer)
- (process-buffer erc-server-process)))
- (current-buffer)))))
- (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
-
-(ert-deftest erc-scenarios-join-network-id--new-invocation ()
- (let ((connect (lambda ()
- (erc :server "127.0.0.1"
- :port (with-current-buffer "foonet"
- (process-contact erc-server-process :service))
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"))))
- (erc-scenarios-common--join-network-id connect nil nil)))
-
-(ert-deftest erc-scenarios-join-network-id--new-invocation-id ()
- (let ((connect (lambda ()
- (erc :server "127.0.0.1"
- :port (with-current-buffer "oofnet"
- (process-contact erc-server-process :service))
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"
- :id 'oofnet))))
- (erc-scenarios-common--join-network-id connect 'oofnet nil)))
-
-(ert-deftest erc-scenarios-join-network-id--new-invocation-ids ()
- (let ((connect (lambda ()
- (erc :server "127.0.0.1"
- :port (with-current-buffer "oofnet"
- (process-contact erc-server-process :service))
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"
- :id 'oofnet))))
- (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
-
-;; Ensure the old way of specifying a partial domain name still works.
-
-(ert-deftest erc-scenarios-base-legacy-autojoin--announced ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "join/legacy")
- (erc-d-linger-secs 1)
- (erc-server-flood-penalty 0.1)
- (dumb-server (erc-d-run "localhost" t 'foonet))
- (port (process-contact dumb-server :service))
- (erc-autojoin-channels-alist '(("libera\\.chat" "#erc")
- ("foonet\\.org" "#chan"))))
-
- (ert-info ("Connect")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (erc-d-t-wait-for 1 (get-buffer "FooNet"))
-
- (ert-info ("Channel buffer #chan autojoined")
- (with-current-buffer (erc-d-t-wait-for 6 (get-buffer "#chan"))
- (erc-d-t-search-for 10 "Live, and be prosperous")))))
-
-(ert-deftest erc-scenarios-join-reconnect ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "join/reconnect")
- (dumb-server (erc-d-run "localhost" t 'foonet 'foonet-again))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-flood-penalty 0.1)
- (erc-server-auto-reconnect t)
- erc-autojoin-channels-alist
- erc-server-buffer)
-
- (should (memq 'autojoin erc-modules))
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (funcall expect 1 "debug mode")))
-
- (ert-info ("Wait for some output in channels")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
- (funcall expect 10 "welcome"))
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
- (funcall expect 10 "welcome")))
-
- (should (equal erc-autojoin-channels-alist '((FooNet "#spam" "#chan"))))
-
- (ert-info ("Wait for auto reconnect")
- (with-current-buffer erc-server-buffer
- (funcall expect 10 "still in debug mode")))
-
- (ert-info ("Wait for activity to recommence in channels")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
- (funcall expect 10 "forest of Arden"))
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
- (funcall expect 10 "her elves come here anon")))))
-
-;; Playback for same channel on two networks routed correctly.
-;; Originally from Bug#48598: 28.0.50; buffer-naming collisions
-;; involving bouncers in ERC.
-
-(ert-deftest erc-scenarios-base-association-bouncer-history ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/association/bouncer-history")
- (erc-d-t-cleanup-sleep-secs 1)
- (erc-d-linger-secs 1)
- (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
- (port (process-contact dumb-server :service))
- (erc-server-flood-penalty 0.5)
- (expect (erc-d-t-make-expecter))
- erc-autojoin-channels-alist
- erc-server-buffer-foo erc-server-process-foo
- erc-server-buffer-bar erc-server-process-bar)
-
- (ert-info ("Connect to foonet")
- (with-current-buffer
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"))
- (setq erc-server-process-foo erc-server-process)
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (funcall expect 5 "foonet")))
-
- (erc-d-t-wait-for 5 (get-buffer "#chan"))
-
- (ert-info ("Connect to barnet")
- (with-current-buffer
- (setq erc-server-buffer-bar (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "barnet:changeme"
- :full-name "tester"))
- (setq erc-server-process-bar erc-server-process)
- (erc-d-t-wait-for 5 "Temporary name assigned"
- (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (funcall expect 5 "barnet")))
-
- (ert-info ("Server buffers are unique")
- (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
-
- (ert-info ("Networks correctly determined and adopted as buffer names")
- (with-current-buffer erc-server-buffer-foo
- (erc-d-t-wait-for 3 "network name foonet becomes buffer name"
- (and (eq (erc-network) 'foonet) (string= (buffer-name) "foonet"))))
- (with-current-buffer erc-server-buffer-bar
- (erc-d-t-wait-for 3 "network name barnet becomes buffer name"
- (and (eq (erc-network) 'barnet) (string= (buffer-name) "barnet")))))
-
- (erc-d-t-wait-for 5 (get-buffer "#chan@barnet"))
-
- (ert-info ("Two channel buffers created, original #chan renamed")
- (should (= 4 (length (erc-buffer-list))))
- (should (equal (list (get-buffer "#chan@barnet")
- (get-buffer "#chan@foonet"))
- (erc-scenarios-common-buflist "#chan"))))
-
- (ert-info ("#chan@foonet is exclusive, no cross-contamination")
- (with-current-buffer "#chan@foonet"
- (erc-d-t-search-for 1 "<bob>")
- (erc-d-t-absent-for 0.1 "<joe>")
- (should (eq erc-server-process erc-server-process-foo))))
-
- (ert-info ("#chan@barnet is exclusive, no cross-contamination")
- (with-current-buffer "#chan@barnet"
- (erc-d-t-search-for 1 "<joe>")
- (erc-d-t-absent-for 0.1 "<bob>")
- (should (eq erc-server-process erc-server-process-bar))))
-
- (ert-info ("All output sent")
- (with-current-buffer "#chan@foonet"
- (while (accept-process-output erc-server-process-foo))
- (erc-d-t-search-for 3 "please your lordship"))
- (with-current-buffer "#chan@barnet"
- (while (accept-process-output erc-server-process-bar))
- (erc-d-t-search-for 3 "I'll bid adieu")))))
-
-(cl-defun erc-scenarios-common--base-network-id-bouncer
- ((&key autop foo-id bar-id after
- &aux
- (foo-id (and foo-id 'oofnet))
- (bar-id (and bar-id 'rabnet))
- (serv-buf-foo (if foo-id "oofnet" "foonet"))
- (serv-buf-bar (if bar-id "rabnet" "barnet"))
- (chan-buf-foo (if foo-id "#chan@oofnet" "#chan@foonet"))
- (chan-buf-bar (if bar-id "#chan@rabnet" "#chan@barnet")))
- &rest dialogs)
- "Ensure retired option `erc-rename-buffers' is now the default behavior.
-The option `erc-rename-buffers' is now deprecated and on by default, so
-this now just asserts baseline behavior. Originally from scenario
-clash-of-chans/rename-buffers as explained in Bug#48598: 28.0.50;
-buffer-naming collisions involving bouncers in ERC."
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/network-id/bouncer")
- (erc-d-t-cleanup-sleep-secs 1)
- (erc-server-flood-penalty 0.1)
- (dumb-server (apply #'erc-d-run "localhost" t dialogs))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-auto-reconnect autop)
- erc-server-buffer-foo erc-server-process-foo
- erc-server-buffer-bar erc-server-process-bar)
-
- (ert-info ("Connect to foonet")
- (with-current-buffer
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"
- :id foo-id))
- (setq erc-server-process-foo erc-server-process)
- (erc-scenarios-common-assert-initial-buf-name foo-id port)
- (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
- (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-foo))
- (funcall expect 5 "foonet")))
-
- (ert-info ("Join #chan@foonet")
- (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
- (funcall expect 5 "<alice>")))
-
- (ert-info ("Connect to barnet")
- (with-current-buffer
- (setq erc-server-buffer-bar (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "barnet:changeme"
- :full-name "tester"
- :id bar-id))
- (setq erc-server-process-bar erc-server-process)
- (erc-scenarios-common-assert-initial-buf-name bar-id port)
- (erc-d-t-wait-for 3 (eq (erc-network) 'barnet))
- (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-bar))
- (funcall expect 5 "barnet")))
-
- (ert-info ("Server buffers are unique, no names based on IPs")
- (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
- (should-not (erc-scenarios-common-buflist "127.0.0.1")))
-
- (ert-info ("Join #chan@barnet")
- (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
-
- (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
- (equal (list (get-buffer chan-buf-bar)
- (get-buffer chan-buf-foo))
- (erc-scenarios-common-buflist "#chan")))
-
- (ert-info ("#chan@<esid> is exclusive to foonet")
- (with-current-buffer chan-buf-foo
- (erc-d-t-search-for 1 "<bob>")
- (erc-d-t-absent-for 0.1 "<joe>")
- (should (eq erc-server-process erc-server-process-foo))
- (while (accept-process-output erc-server-process-foo))
- (erc-d-t-search-for 1 "ape is dead")
- (should-not (erc-server-process-alive))))
-
- (ert-info ("#chan@<esid> is exclusive to barnet")
- (with-current-buffer chan-buf-bar
- (erc-d-t-search-for 1 "<joe>")
- (erc-d-t-absent-for 0.1 "<bob>")
- (should (eq erc-server-process erc-server-process-bar))
- (while (accept-process-output erc-server-process-bar))
- (erc-d-t-search-for 1 "keeps you from dishonour")
- (should-not (erc-server-process-alive))))
-
- (when after (funcall after))))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--base ()
- (erc-scenarios-common--base-network-id-bouncer () 'foonet 'barnet))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--id-foo ()
- (erc-scenarios-common--base-network-id-bouncer '(:foo-id t) 'foonet 'barnet))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--id-bar ()
- (erc-scenarios-common--base-network-id-bouncer '(:bar-id t) 'foonet 'barnet))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--both ()
- (erc-scenarios-common--base-network-id-bouncer '(:foo-id t :bar-id t)
- 'foonet 'barnet))
-
-(defun erc-scenarios--clash-rename-pass-handler (dialog exchange)
- (when (eq (erc-d-dialog-name dialog) 'stub-again)
- (let* ((match (erc-d-exchange-match exchange 1))
- (sym (if (string= match "foonet") 'foonet-again 'barnet-again)))
- (should (member match (list "foonet" "barnet")))
- (erc-d-load-replacement-dialog dialog sym 1))))
-
-(defun erc-scenarios-common--base-network-id-bouncer--reconnect (foo-id bar-id)
- (let ((erc-d-spec-vars '((token . (group (| "barnet" "foonet")))))
- (erc-d-match-handlers
- ;; Auto reconnect is nondeterministic, so let computer decide
- (list :pass #'erc-scenarios--clash-rename-pass-handler))
- (after
- (lambda ()
- ;; Simulate disconnection and `erc-server-auto-reconnect'
- (ert-info ("Reconnect to foonet and barnet back-to-back")
- (with-current-buffer (if foo-id "oofnet" "foonet")
- (erc-d-t-wait-for 5 (erc-server-process-alive)))
- (with-current-buffer (if bar-id "rabnet" "barnet")
- (erc-d-t-wait-for 5 (erc-server-process-alive))))
-
- (ert-info ("#chan@foonet is exclusive to foonet")
- (with-current-buffer (if foo-id "#chan@oofnet" "#chan@foonet")
- (erc-d-t-search-for 1 "<alice>")
- (erc-d-t-absent-for 0.1 "<joe>")
- (while (accept-process-output erc-server-process))
- (erc-d-t-search-for 3 "please your lordship")))
-
- (ert-info ("#chan@barnet is exclusive to barnet")
- (with-current-buffer (if bar-id "#chan@rabnet" "#chan@barnet")
- (erc-d-t-search-for 1 "<joe>")
- (erc-d-t-absent-for 0.1 "<bob>")
- (while (accept-process-output erc-server-process))
- (erc-d-t-search-for 1 "much in private")))
-
- ;; XXX this is important (reconnects overlapped, so we'd get
- ;; chan@127.0.0.1:6667)
- (should-not (erc-scenarios-common-buflist "127.0.0.1"))
- ;; Reconnection order doesn't matter here because session objects
- ;; are persisted, meaning original timestamps preserved.
- (should (equal (list (get-buffer (if bar-id "#chan@rabnet"
- "#chan@barnet"))
- (get-buffer (if foo-id "#chan@oofnet"
- "#chan@foonet")))
- (erc-scenarios-common-buflist "#chan"))))))
- (erc-scenarios-common--base-network-id-bouncer
- (list :autop t :foo-id foo-id :bar-id bar-id :after after)
- 'foonet-drop 'barnet-drop
- 'stub-again 'stub-again
- 'foonet-again 'barnet-again)))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--reconnect-base ()
- (erc-scenarios-common--base-network-id-bouncer--reconnect nil nil))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--reconnect-id-foo ()
- (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id nil))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--reconnect-id-bar ()
- (erc-scenarios-common--base-network-id-bouncer--reconnect nil 'bar-id))
-
-(ert-deftest erc-scenarios-base-network-id-bouncer--reconnect-both ()
- (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id 'bar-id))
-
-;; Ensure deprecated option still respected when old default value
-;; explicitly set ("respected" in the sense of having names reflect
-;; dialed TCP endpoints with possible uniquifiers but without any of
-;; the old issues, pre-bug#48598).
-
-(defun erc-scenarios-common--base-compat-no-rename-bouncer (dialogs auto more)
- (erc-scenarios-common-with-cleanup
- ;; These actually *are* (assigned-)network-id related because
- ;; our kludge assigns one after the fact.
- ((erc-scenarios-common-dialog "base/network-id/bouncer")
- (erc-d-t-cleanup-sleep-secs 1)
- (erc-server-flood-penalty 0.1)
- (dumb-server (apply #'erc-d-run "localhost" t dialogs))
- (port (process-contact dumb-server :service))
- (chan-buf-foo (format "#chan@127.0.0.1:%d" port))
- (chan-buf-bar (format "#chan@127.0.0.1:%d<2>" port))
- (expect (erc-d-t-make-expecter))
- (erc-server-auto-reconnect auto)
- erc-server-buffer-foo erc-server-process-foo
- erc-server-buffer-bar erc-server-process-bar)
-
- (ert-info ("Connect to foonet")
- (with-current-buffer
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"
- :id nil))
- (setq erc-server-process-foo erc-server-process)
- (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
- (erc-d-t-wait-for 3 "Final buffer name determined"
- (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (funcall expect 5 "foonet")))
-
- (ert-info ("Join #chan@foonet")
- (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
- (funcall expect 5 "<alice>")))
-
- (ert-info ("Connect to barnet")
- (with-current-buffer
- (setq erc-server-buffer-bar (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "barnet:changeme"
- :full-name "tester"
- :id nil))
- (setq erc-server-process-bar erc-server-process)
- (erc-d-t-wait-for 3 (eq (erc-network) 'barnet))
- (erc-d-t-wait-for 3 "Final buffer name determined"
- (string= (buffer-name) (format "127.0.0.1:%d<2>" port)))
- (funcall expect 5 "barnet")))
-
- (ert-info ("Server buffers are unique, no names based on IPs")
- (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
- (should (equal (erc-scenarios-common-buflist "127.0.0.1")
- (list (get-buffer (format "127.0.0.1:%d<2>" port))
- (get-buffer (format "127.0.0.1:%d" port))))))
-
- (ert-info ("Join #chan@barnet")
- (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
-
- (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
- (equal (list (get-buffer chan-buf-bar)
- (get-buffer chan-buf-foo))
- (erc-scenarios-common-buflist "#chan")))
-
- (ert-info ("#chan@127.0.0.1:$port is exclusive to foonet")
- (with-current-buffer chan-buf-foo
- (erc-d-t-search-for 1 "<bob>")
- (erc-d-t-absent-for 0.1 "<joe>")
- (should (eq erc-server-process erc-server-process-foo))
- (while (accept-process-output erc-server-process-foo))
- (erc-d-t-search-for 1 "ape is dead")
- (should-not (erc-server-process-alive))))
-
- (ert-info ("#chan@127.0.0.1:$port<2> is exclusive to barnet")
- (with-current-buffer chan-buf-bar
- (erc-d-t-search-for 1 "<joe>")
- (erc-d-t-absent-for 0.1 "<bob>")
- (should (eq erc-server-process erc-server-process-bar))
- (while (accept-process-output erc-server-process-bar))
- (erc-d-t-search-for 1 "keeps you from dishonour")
- (should-not (erc-server-process-alive))))
-
- (when more (funcall more))))
-
-(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--basic ()
- (with-suppressed-warnings ((obsolete erc-rename-buffers))
- (let (erc-rename-buffers)
- (erc-scenarios-common--base-compat-no-rename-bouncer
- '(foonet barnet) nil nil))))
-
-(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--reconnect ()
- (let ((erc-d-spec-vars '((token . (group (| "barnet" "foonet")))))
- (erc-d-match-handlers
- (list :pass #'erc-scenarios--clash-rename-pass-handler))
- (dialogs '(foonet-drop barnet-drop stub-again stub-again
- foonet-again barnet-again))
- (after
- (lambda ()
- (pcase-let* ((`(,barnet ,foonet)
- (erc-scenarios-common-buflist "127.0.0.1"))
- (port (process-contact (with-current-buffer foonet
- erc-server-process)
- :service)))
-
- (ert-info ("Sanity check: barnet retains uniquifying suffix")
- (should (string-suffix-p "<2>" (buffer-name barnet))))
-
- ;; Simulate disconnection and `erc-server-auto-reconnect'
- (ert-info ("Reconnect to foonet and barnet back-to-back")
- (with-current-buffer foonet
- (erc-d-t-wait-for 5 (erc-server-process-alive)))
- (with-current-buffer barnet
- (erc-d-t-wait-for 5 (erc-server-process-alive))))
-
- (ert-info ("#chan@127.0.0.1:<port> is exclusive to foonet")
- (with-current-buffer (format "#chan@127.0.0.1:%d" port)
- (erc-d-t-search-for 1 "<alice>")
- (erc-d-t-absent-for 0.1 "<joe>")
- (while (accept-process-output erc-server-process))
- (erc-d-t-search-for 3 "please your lordship")))
-
- (ert-info ("#chan@barnet is exclusive to barnet")
- (with-current-buffer (format "#chan@127.0.0.1:%d<2>" port)
- (erc-d-t-search-for 1 "<joe>")
- (erc-d-t-absent-for 0.1 "<bob>")
- (while (accept-process-output erc-server-process))
- (erc-d-t-search-for 1 "much in private")))
-
- ;; Ordering deterministic here even though not so for reconnect
- (should (equal (list barnet foonet)
- (erc-scenarios-common-buflist "127.0.0.1")))
- (should (equal (list
- (get-buffer (format "#chan@127.0.0.1:%d<2>" port))
- (get-buffer (format "#chan@127.0.0.1:%d" port)))
- (erc-scenarios-common-buflist "#chan")))))))
-
- (with-suppressed-warnings ((obsolete erc-rename-buffers))
- (let (erc-rename-buffers)
- (erc-scenarios-common--base-compat-no-rename-bouncer dialogs
- 'auto after)))))
-
-;; The added complexity of a request handler definitely stinks. But on
-;; some machines, the ordering from the selector is nondeterministic,
-;; whereas normally, the filter for the last process created (in the
-;; code) gets all the initial attention. FIXME delete obsolete comment
-
-(defun erc-scenarios--rebuffed-gapless-pass-handler (dialog exchange)
- (when (eq (erc-d-dialog-name dialog) 'pass-stub)
- (let* ((match (erc-d-exchange-match exchange 1))
- (sym (if (string= match "foonet") 'foonet 'barnet)))
- (should (member match (list "foonet" "barnet")))
- (erc-d-load-replacement-dialog dialog sym 1))))
-
-(ert-deftest erc-scenarios-base-gapless-connect ()
- "Back-to-back entry-point invocations happen successfully.
-Originally from scenario rebuffed/gapless as explained in Bug#48598:
-28.0.50; buffer-naming collisions involving bouncers in ERC."
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/gapless-connect")
- (erc-server-flood-penalty 0.1)
- (erc-d-linger-secs 4)
- (erc-server-flood-penalty erc-server-flood-penalty)
- (erc-d-spec-vars '((token . (group (| "barnet" "foonet")))))
- (erc-d-match-handlers
- (list :pass #'erc-scenarios--rebuffed-gapless-pass-handler))
- (dumb-server (erc-d-run "localhost" t
- 'pass-stub 'pass-stub 'barnet 'foonet))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- erc-autojoin-channels-alist
- erc-server-buffer-foo
- erc-server-buffer-bar)
-
- (ert-info ("Connect twice to same endpoint without pausing")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester")
- erc-server-buffer-bar (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "barnet:changeme"
- :full-name "tester")))
-
- (ert-info ("Returned server buffers are unique")
- (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
-
- (ert-info ("Both connections still alive")
- (should (get-process (format "erc-127.0.0.1-%d" port)))
- (should (get-process (format "erc-127.0.0.1-%d<1>" port))))
-
- (with-current-buffer erc-server-buffer-bar
- (funcall expect 2 "marked as being away"))
-
- (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#bar"))
- (while (accept-process-output erc-server-process))
- (funcall expect 2 "was created on")
- (funcall expect 2 "his second fit"))
-
- (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#foo"))
- (while (accept-process-output erc-server-process))
- (funcall expect 2 "was created on")
- (funcall expect 2 "no use of him"))))
-
-(defun erc-scenarios-common--base-reuse-buffers-server-buffers (&optional more)
- "Show that `erc-reuse-buffers' doesn't affect server buffers.
-Overlaps some with `clash-of-chans/uniquify'. Adapted from
-rebuffed/reuseless, described in Bug#48598: 28.0.50; buffer-naming
-collisions involving bouncers in ERC. Run EXTRA."
- (erc-scenarios-common-with-cleanup
- ((erc-d-linger-secs 1)
- (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
- (port (process-contact dumb-server :service))
- erc-autojoin-channels-alist)
-
- (ert-info ("Connect to foonet")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (erc-d-t-search-for 2 "marked as being away")))
-
- (ert-info ("Connect to barnet")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "barnet:changeme"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (erc-d-t-search-for 2 "marked as being away")))
-
- (erc-d-t-wait-for 2 (get-buffer "foonet"))
- (erc-d-t-wait-for 2 (get-buffer "barnet"))
-
- (ert-info ("Server buffers are unique, no IP-based names")
- (should-not (eq (get-buffer "foonet") (get-buffer "barnet")))
- (should-not (erc-scenarios-common-buflist "127.0.0.1")))
-
- (when more (funcall more))))
-
-(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--enabled ()
- (should erc-reuse-buffers)
- (let ((erc-scenarios-common-dialog "base/reuse-buffers/server-buffers"))
- (erc-scenarios-common--base-reuse-buffers-server-buffers)))
-
-(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--disabled ()
- (should erc-reuse-buffers)
- (let ((erc-scenarios-common-dialog "base/reuse-buffers/server-buffers")
- erc-reuse-buffers)
- (erc-scenarios-common--base-reuse-buffers-server-buffers)))
-
-;; This also asserts that `erc-cmd-JOIN' is no longer susceptible to a
-;; regression introduced in 28.1 (ERC 5.4) that caused phantom target
-;; buffers of the form target/server to be created via
-;; `switch-to-buffer' ("phantom" because they would go unused"). This
-;; would happen (in place of a JOIN being sent out) when a previously
-;; used (parted) target buffer existed and `erc-reuse-buffers' was
-;; nil.
-;;
-;; Note: All the `erc-get-channel-user' calls have to do with the fact
-;; that `erc-default-target' relies on the less-than-well-defined
-;; `erc-default-recipients' and is thus overloaded in the sense of
-;; being used both for retrieving a target name and checking if
-;; channel has been PARTed. While not ideal, `erc-get-channel-user'
-;; can (also) be used to detect the latter.
-
-(defun erc-scenarios-common--base-reuse-buffers-channel-buffers ()
- "The option `erc-reuse-buffers' is still respected when nil.
-Adapted from scenario clash-of-chans/uniquify described in Bug#48598:
-28.0.50; buffer-naming collisions involving bouncers in ERC."
- (let ((expect (erc-d-t-make-expecter))
- (server-process-bar (with-current-buffer "barnet" erc-server-process))
- (server-process-foo (with-current-buffer "foonet" erc-server-process)))
-
- (ert-info ("Unique #chan buffers exist")
- (let ((chan-bufs (erc-scenarios-common-buflist "#chan"))
- (names '("#chan@barnet" "#chan@foonet")))
- (should (member (buffer-name (pop chan-bufs)) names))
- (should (member (buffer-name (pop chan-bufs)) names))
- (should-not chan-bufs)))
-
- (ert-info ("#chan@foonet is exclusive and not contaminated")
- (with-current-buffer "#chan@foonet"
- (funcall expect 1 "<bob>")
- (erc-d-t-absent-for 0.1 "<joe>")
- (funcall expect 1 "strength to climb")
- (should (eq erc-server-process server-process-foo))))
-
- (ert-info ("#chan@barnet is exclusive and not contaminated")
- (with-current-buffer "#chan@barnet"
- (funcall expect 1 "<joe>")
- (erc-d-t-absent-for 0.1 "<bob>")
- (funcall expect 1 "the loudest noise")
- (should (eq erc-server-process server-process-bar))))
-
- (ert-info ("Part #chan@foonet")
- (with-current-buffer "#chan@foonet"
- (erc-d-t-search-for 1 "shake my sword")
- (erc-cmd-PART "#chan")
- (funcall expect 3 "You have left channel #chan")
- (erc-cmd-JOIN "#chan")))
-
- (ert-info ("Part #chan@barnet")
- (with-current-buffer "#chan@barnet"
- (funcall expect 3 "Arm it in rags")
- (should (erc-get-channel-user (erc-current-nick)))
- (erc-cmd-PART "#chan")
- (funcall expect 3 "You have left channel #chan")
- (should-not (erc-get-channel-user (erc-current-nick)))
- (erc-cmd-JOIN "#chan")))
-
- (erc-d-t-wait-for 3 "New unique target buffer for #chan@foonet created"
- (get-buffer "#chan@foonet<2>"))
-
- (ert-info ("Activity continues in new, <n>-suffixed #chan@foonet buffer")
- (with-current-buffer "#chan@foonet"
- (should-not (erc-get-channel-user (erc-current-nick))))
- (with-current-buffer "#chan@foonet<2>"
- (should (erc-get-channel-user (erc-current-nick)))
- (funcall expect 2 "You have joined channel #chan")
- (funcall expect 2 "#chan was created on")
- (funcall expect 2 "<alice>")
- (should (eq erc-server-process server-process-foo))
- (erc-d-t-absent-for 0.2 "<joe>")))
-
- (erc-d-t-wait-for 3 "New unique target buffer for #chan@barnet created"
- (get-buffer "#chan@barnet<2>"))
-
- (ert-info ("Activity continues in new, <n>-suffixed #chan@barnet buffer")
- (with-current-buffer "#chan@barnet"
- (should-not (erc-get-channel-user (erc-current-nick))))
- (with-current-buffer "#chan@barnet<2>"
- (funcall expect 2 "You have joined channel #chan")
- (funcall expect 1 "Users on #chan: @mike joe tester")
- (funcall expect 2 "<mike>")
- (should (eq erc-server-process server-process-bar))
- (erc-d-t-absent-for 0.2 "<bob>")))
-
- (ert-info ("Two new chans created for a total of four")
- (let* ((bufs (erc-scenarios-common-buflist "#chan"))
- (names (sort (mapcar #'buffer-name bufs) #'string<)))
- (should (equal names '("#chan@barnet" "#chan@barnet<2>"
- "#chan@foonet" "#chan@foonet<2>")))))
-
- (ert-info ("All output sent")
- (with-current-buffer "#chan@foonet<2>"
- (while (accept-process-output server-process-foo))
- (funcall expect 3 "most lively"))
- (with-current-buffer "#chan@barnet<2>"
- (while (accept-process-output server-process-bar))
- (funcall expect 3 "soul black")))))
-
-(ert-deftest erc-scenarios-base-reuse-buffers-channel-buffers--disabled ()
- (should erc-reuse-buffers)
- (let ((erc-scenarios-common-dialog "base/reuse-buffers/channel-buffers")
- (erc-server-flood-penalty 0.1)
- erc-reuse-buffers)
- (erc-scenarios-common--base-reuse-buffers-server-buffers
- #'erc-scenarios-common--base-reuse-buffers-channel-buffers)))
-
-;; The server changes your nick just after registration.
-
-(ert-deftest erc-scenarios-base-renick-self-auto ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/renick/self")
- (erc-d-linger-secs 0.1)
- (erc-server-flood-penalty 0.1)
- (dumb-server (erc-d-run "localhost" t 'auto))
- (port (process-contact dumb-server :service))
- erc-autojoin-channels-alist
- erc-server-buffer-foo)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
- (erc-d-t-search-for 10 "Your new nickname is dummy"))
-
- (ert-info ("Joined by bouncer to #foo, own nick present")
- (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
- (erc-d-t-search-for 10 "dummy")
- (erc-d-t-search-for 10 "On Thursday")))))
-
-;; You change your nickname manually in a server buffer; a message is
-;; printed in channel buffers.
-
-(ert-deftest erc-scenarios-base-renick-self-manual ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/renick/self")
- (erc-d-linger-secs 0.1)
- (erc-server-flood-penalty 0.1)
- (dumb-server (erc-d-run "localhost" t 'manual))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- erc-autojoin-channels-alist
- erc-server-buffer-foo)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (erc-d-t-wait-for 3 (get-buffer "foonet"))
-
- (ert-info ("Joined by bouncer to #foo, own nick present")
- (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
- (funcall expect 5 "tester")
- (funcall expect 5 "On Thursday")
- (erc-with-server-buffer (erc-cmd-NICK "dummy"))
- (funcall expect 5 "Your new nickname is dummy")
- (funcall expect 5 "<bob> dummy: Hi")
- ;; Regression in which changing a nick would trigger #foo@foonet
- (erc-d-t-ensure-for 0.4 (equal (buffer-name) "#foo"))))))
-
-;; You connect to the same network with two different nicks. You
-;; manually change the first nick at some point, and buffer names are
-;; updated correctly.
-
-(ert-deftest erc-scenarios-base-renick-self-qualified ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/renick/self")
- (dumb-server (erc-d-run "localhost" t 'qual-tester 'qual-chester))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-flood-penalty 0.1)
- (erc-server-flood-margin 30)
- erc-serv-buf-a erc-serv-buf-b)
-
- (ert-info ("Connect to foonet with nick tester")
- (with-current-buffer
- (setq erc-serv-buf-a (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
-
- (ert-info ("Connect to foonet with nick chester")
- (with-current-buffer
- (setq erc-serv-buf-b (erc :server "127.0.0.1"
- :port port
- :nick "chester"
- :password "changeme"
- :full-name "chester"))))
-
- (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
- (not (erc-scenarios-common-buflist "127.0.0.1")))
-
- (with-current-buffer "foonet/tester"
- (funcall expect 3 "debug mode")
- (erc-cmd-JOIN "#chan"))
-
- (with-current-buffer "foonet/chester"
- (funcall expect 3 "debug mode")
- (erc-cmd-JOIN "#chan"))
-
- (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
- (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
-
- (ert-info ("Greets other nick in same channel")
- (with-current-buffer "#chan@foonet/tester"
- (funcall expect 5 "<bob> chester, welcome!")
- (erc-cmd-NICK "dummy")
- (funcall expect 5 "Your new nickname is dummy")
- (funcall expect 5 "find the forester")
- (erc-d-t-wait-for 5 (string= (buffer-name) "#chan@foonet/dummy"))))
-
- (ert-info ("Renick propagated throughout all buffers of process")
- (should-not (get-buffer "#chan@foonet/tester"))
- (should-not (get-buffer "foonet/tester"))
- (should (get-buffer "foonet/dummy")))))
-
-;; When a channel user changes their nick, any query buffers for them
-;; are updated.
-
-(ert-deftest erc-scenarios-base-renick-queries-solo ()
-
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/renick/queries")
- (erc-d-linger-secs 0.1)
- (erc-server-flood-penalty 0.1)
- (erc-server-flood-margin 20)
- (dumb-server (erc-d-run "localhost" t 'solo))
- (port (process-contact dumb-server :service))
- erc-autojoin-channels-alist
- erc-server-buffer-foo)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (erc-d-t-wait-for 1 (get-buffer "foonet"))
-
- (ert-info ("Joined by bouncer to #foo, pal persent")
- (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
- (erc-d-t-search-for 1 "On Thursday")
- (goto-char erc-input-marker)
- (insert "hi")
- (erc-send-current-line)))
-
- (erc-d-t-wait-for 10 "Query buffer appears with message from pal"
- (get-buffer "Lal"))
-
- (ert-info ("Chat with pal, who changes name")
- (with-current-buffer "Lal"
- (erc-d-t-search-for 3 "hello")
- (goto-char erc-input-marker)
- (insert "hi")
- (erc-send-current-line)
- (erc-d-t-search-for 10 "is now known as Linguo")
- (should-not (search-forward "is now known as Linguo" nil t))))
-
- (erc-d-t-wait-for 1 (get-buffer "Linguo"))
- (should-not (get-buffer "Lal"))
-
- (with-current-buffer "Linguo"
- (goto-char erc-input-marker)
- (insert "howdy Linguo")
- (erc-send-current-line))
-
- (with-current-buffer "#foo"
- (erc-d-t-search-for 10 "is now known as Linguo")
- (should-not (search-forward "is now known as Linguo" nil t))
- (erc-cmd-PART ""))
-
- (with-current-buffer "Linguo"
- (erc-d-t-search-for 10 "get along"))))
-
-;; You share a channel and a query buffer with a user on two different
-;; networks (through a proxy). The user changes their nick on both
-;; networks at the same time. Query buffers are updated accordingly.
-
-(ert-deftest erc-scenarios-base-renick-queries-bouncer ()
-
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/renick/queries")
- (erc-d-linger-secs 0.5)
- (erc-server-flood-penalty 0.1)
- (erc-server-flood-margin 30)
- (dumb-server (erc-d-run "localhost" t 'bouncer-foonet 'bouncer-barnet))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- erc-accidental-paste-threshold-seconds
- erc-autojoin-channels-alist
- erc-server-buffer-foo
- erc-server-buffer-bar)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (erc-d-t-wait-for 1 (get-buffer "foonet"))
-
- (ert-info ("Connect to barnet")
- (setq erc-server-buffer-bar (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "barnet:changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-bar
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (erc-d-t-wait-for 1 (get-buffer "barnet"))
- (should-not (erc-scenarios-common-buflist "127.0.0.1"))
-
- (ert-info ("Joined by bouncer to #chan@foonet, pal persent")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@foonet"))
- (funcall expect 1 "rando")
- (funcall expect 1 "simply misused")))
-
- (ert-info ("Joined by bouncer to #chan@barnet, pal persent")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@barnet"))
- (funcall expect 1 "rando")
- (funcall expect 1 "come, sir, I am")))
-
- (ert-info ("Query buffer exists for rando@foonet")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@foonet"))
- (funcall expect 1 "guess not")
- (goto-char erc-input-marker)
- (insert "I here")
- (erc-send-current-line)))
-
- (ert-info ("Query buffer exists for rando@barnet")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@barnet"))
- (funcall expect 2 "rentacop")
- (goto-char erc-input-marker)
- (insert "Linda said you were gonna kill me.")
- (erc-send-current-line)))
-
- (ert-info ("Sync convo for rando@foonet")
- (with-current-buffer "rando@foonet"
- (funcall expect 1 "u are dumb")
- (goto-char erc-input-marker)
- (insert "not so")
- (erc-send-current-line)))
-
- (ert-info ("Sync convo for rando@barnet")
- (with-current-buffer "rando@barnet"
- (funcall expect 3 "I never saw her before")
- (goto-char erc-input-marker)
- (insert "You aren't with Wage?")
- (erc-send-current-line)))
-
- (erc-d-t-wait-for 1 (get-buffer "frenemy@foonet"))
- (erc-d-t-wait-for 1 (get-buffer "frenemy@barnet"))
- (should-not (get-buffer "rando@foonet"))
- (should-not (get-buffer "rando@barnet"))
-
- (with-current-buffer "frenemy@foonet"
- (funcall expect 1 "now known as")
- (funcall expect 1 "doubly so"))
-
- (with-current-buffer "frenemy@barnet"
- (funcall expect 1 "now known as")
- (funcall expect 1 "reality picture"))
-
- (when noninteractive
- (with-current-buffer "frenemy@barnet" (kill-buffer))
- (erc-d-t-wait-for 2 (get-buffer "frenemy"))
- (should-not (get-buffer "frenemy@foonet")))
-
- (with-current-buffer "#chan@foonet"
- (funcall expect 10 "is now known as frenemy")
- (should-not (search-forward "now known as frenemy" nil t)) ; regression
- (funcall expect 10 "words are razors"))
-
- (with-current-buffer "#chan@barnet"
- (funcall expect 10 "is now known as frenemy")
- (should-not (search-forward "now known as frenemy" nil t))
- (while (accept-process-output erc-server-process))
- (funcall expect 10 "I have lost"))))
-
-(ert-deftest erc-scenarios-aux-unix-socket ()
- (skip-unless (featurep 'make-network-process '(:family local)))
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/renick/self")
- (erc-d-linger-secs 0.1)
- (erc-server-flood-penalty 0.1)
- (sock (expand-file-name "erc-d.sock" temporary-file-directory))
- (erc-scenarios-common-extra-teardown (lambda ()
- (delete-file sock)))
- (erc-server-connect-function
- (lambda (n b _ p &rest r)
- (apply #'make-network-process
- `(:name ,n :buffer ,b :service ,p :family local ,@r))))
- (dumb-server (erc-d-run nil sock 'auto))
- erc-autojoin-channels-alist
- erc-server-buffer-foo)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "fake"
- :port sock
- :nick "tester"
- :password "foonet:changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "fake:%s" sock)))))
-
- (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
- (erc-d-t-search-for 10 "Your new nickname is dummy"))
-
- (ert-info ("Joined by bouncer to #foo, own nick present")
- (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
- (erc-d-t-search-for 10 "dummy")
- (erc-d-t-search-for 10 "On Thursday")))))
-
-;; See `erc-update-server-buffer-name'. A perceived loss in
-;; network connectivity turns out to be a false alarm, but the
-;; bouncer has already accepted the second connection
-
-(defun erc-scenarios--base-aborted-reconnect ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/reconnect")
- (erc-d-t-cleanup-sleep-secs 1)
- (erc-d-linger-secs 0.5)
- (dumb-server (erc-d-run "localhost" t 'aborted 'aborted-dupe))
- (port (process-contact dumb-server :service))
- erc-autojoin-channels-alist
- erc-server-buffer-foo)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (ert-info ("Server buffer is unique and temp name is absent")
- (erc-d-t-wait-for 1 (get-buffer "FooNet"))
- (should-not (erc-scenarios-common-buflist "127.0.0.1"))
- (with-current-buffer erc-server-buffer-foo
- (erc-cmd-JOIN "#chan")))
-
- (ert-info ("Channel buffer #chan alive and well")
- (with-current-buffer (erc-d-t-wait-for 4 (get-buffer "#chan"))
- (erc-d-t-search-for 10 "welcome")))
-
- (ert-info ("Connect to foonet again")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (let ((inhibit-message noninteractive))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (erc-d-t-wait-for 5 (not (erc-server-process-alive)))
- (erc-d-t-search-for 10 "FooNet still connected"))))
-
- (ert-info ("Server buffer is unique and temp name is absent")
- (should (equal (list (get-buffer "FooNet"))
- (erc-scenarios-common-buflist "FooNet")))
- (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
- (erc-scenarios-common-buflist "127.0.0.1"))))
-
- (ert-info ("Channel buffer #chan still going")
- (with-current-buffer "#chan"
- (erc-d-t-search-for 10 "and be prosperous")))))
-
-(ert-deftest erc-scenarios-base-aborted-reconnect ()
- :tags '(:unstable)
- (let ((tries 3)
- (timeout 1)
- failed)
- (while (condition-case _err
- (progn
- (erc-scenarios--base-aborted-reconnect)
- nil)
- (ert-test-failed
- (message "Test %S failed; %s attempt(s) remaining."
- (ert-test-name (ert-running-test))
- tries)
- (sleep-for (cl-incf timeout))
- (not (setq failed (zerop (cl-decf tries)))))))
- (should-not failed)))
-
-;; This defends against a regression in `erc-server-PRIVMSG' caused by
-;; the removal of `erc-auto-query'. When an active channel buffer is
-;; killed off and PRIVMSGs arrive targeting it, the buffer should be
-;; recreated. See elsewhere for NOTICE logic, which is more complex.
-
-(ert-deftest erc-scenarios-base-channel-buffer-revival ()
-
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/channel-buffer-revival")
- (erc-d-linger-secs 0.5)
- (dumb-server (erc-d-run "localhost" t 'foonet))
- (port (process-contact dumb-server :service))
- erc-autojoin-channels-alist
- erc-server-buffer-foo)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (ert-info ("Server buffer is unique and temp name is absent")
- (erc-d-t-wait-for 1 (get-buffer "FooNet"))
- (should-not (erc-scenarios-common-buflist "127.0.0.1"))
- (with-current-buffer erc-server-buffer-foo
- (erc-cmd-JOIN "#chan")))
-
- (ert-info ("Channel buffer #chan alive and well")
- (with-current-buffer (erc-d-t-wait-for 8 (get-buffer "#chan"))
- (erc-d-t-search-for 10 "Our queen and all her elves")
- (kill-buffer)))
-
- (should-not (get-buffer "#chan"))
-
- (ert-info ("Channel buffer #chan revived")
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
- (erc-d-t-search-for 10 "and be prosperous")))))
-
-;; This ensures we only reconnect `erc-server-reconnect-attempts'
-;; (rather than infinitely many) times, which can easily happen when
-;; tweaking code related to process sentinels in erc-backend.el.
-
-(ert-deftest erc-scenarios-base-reconnect-timer ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/reconnect")
- (dumb-server (erc-d-run "localhost" t 'timer 'timer 'timer-last))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-auto-reconnect t)
- erc-autojoin-channels-alist
- erc-server-buffer)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (ert-info ("Server tries to connect thrice (including initial attempt)")
- (with-current-buffer erc-server-buffer
- (dotimes (n 3)
- (ert-info ((format "Attempt %d" n))
- (funcall expect 3 "Opening connection")
- (funcall expect 2 "Password incorrect")
- (funcall expect 2 "Connection failed!")
- (funcall expect 2 "Re-establishing connection")))
- (ert-info ("Prev attempt was final")
- (erc-d-t-absent-for 1 "Opening connection" (point)))))
-
- (ert-info ("Server buffer is unique and temp name is absent")
- (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
- (erc-scenarios-common-buflist "127.0.0.1"))))))
-
-(defun erc-scenarios-common--base-reconnect-options (test)
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/reconnect")
- (dumb-server (erc-d-run "localhost" t 'options 'options-again))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-flood-penalty 0.1)
- (erc-server-auto-reconnect t)
- erc-autojoin-channels-alist
- erc-server-buffer)
-
- (should (memq 'autojoin erc-modules))
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (funcall expect 1 "debug mode")))
-
- (ert-info ("Wait for some output in channels")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
- (funcall expect 10 "welcome")))
-
- (ert-info ("Server buffer shows connection failed")
- (with-current-buffer erc-server-buffer
- (funcall expect 10 "Connection failed! Re-establishing")))
-
- (should (equal erc-autojoin-channels-alist '((FooNet "#chan"))))
-
- (funcall test)
-
- (with-current-buffer "FooNet" (erc-cmd-JOIN "#spam"))
-
- (erc-d-t-wait-for 5 "Channel #spam shown when autojoined"
- (eq (window-buffer) (get-buffer "#spam")))
-
- (ert-info ("Wait for auto reconnect")
- (with-current-buffer erc-server-buffer
- (funcall expect 10 "still in debug mode")))
-
- (ert-info ("Wait for activity to recommence in channels")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
- (funcall expect 10 "forest of Arden"))
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
- (funcall expect 10 "her elves come here anon")))))
-
-(ert-deftest erc-scenarios-base-reconnect-options--default ()
- (should (eq erc-join-buffer 'buffer))
- (should-not erc-reconnect-display)
-
- ;; FooNet (the server buffer) is not switched to because it's
- ;; already current (but not shown) when `erc-open' is called. See
- ;; related conditional guard towards the end of that function.
-
- (erc-scenarios-common--base-reconnect-options
- (lambda ()
- (pop-to-buffer-same-window "*Messages*")
-
- (erc-d-t-ensure-for 1 "Server buffer not shown"
- (not (eq (window-buffer) (get-buffer "FooNet"))))
-
- (erc-d-t-wait-for 5 "Channel #chan shown when autojoined"
- (eq (window-buffer) (get-buffer "#chan"))))))
-
-(ert-deftest erc-scenarios-base-reconnect-options--bury ()
- (should (eq erc-join-buffer 'buffer))
- (should-not erc-reconnect-display)
-
- (let ((erc-reconnect-display 'bury))
- (erc-scenarios-common--base-reconnect-options
-
- (lambda ()
- (pop-to-buffer-same-window "*Messages*")
-
- (erc-d-t-ensure-for 1 "Server buffer not shown"
- (not (eq (window-buffer) (get-buffer "FooNet"))))
-
- (erc-d-t-ensure-for 3 "Channel #chan not shown"
- (not (eq (window-buffer) (get-buffer "#chan"))))
-
- (eq (window-buffer) (messages-buffer))))))
-
-(cl-defun erc-scenarios-common--base-network-id-same-network
- ((&key nick id server chan
- &aux (nick-a nick) (id-a id) (serv-buf-a server) (chan-buf-a chan))
- (&key nick id server chan
- &aux (nick-b nick) (id-b id) (serv-buf-b server) (chan-buf-b chan)))
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/network-id/same-network")
- (dumb-server (erc-d-run "localhost" t 'tester 'chester))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-flood-penalty 0.1)
- (erc-server-flood-margin 30)
- erc-serv-buf-a erc-serv-buf-b)
-
- (ert-info ("Connect to foonet with nick tester")
- (with-current-buffer
- (setq erc-serv-buf-a (erc :server "127.0.0.1"
- :port port
- :nick nick-a
- :password "changeme"
- :full-name nick-a
- :id id-a))
- (erc-scenarios-common-assert-initial-buf-name id-a port)
- (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
-
- (ert-info ("Connect to foonet with nick chester")
- (with-current-buffer
- (setq erc-serv-buf-b (erc :server "127.0.0.1"
- :port port
- :nick nick-b
- :password "changeme"
- :full-name nick-b
- :id id-b))
- (erc-scenarios-common-assert-initial-buf-name id-b port)))
-
- (erc-d-t-wait-for 3 (not (erc-scenarios-common-buflist "127.0.0.1")))
-
- (with-current-buffer erc-serv-buf-a
- (should (string= (buffer-name) serv-buf-a))
- (funcall expect 3 "debug mode")
- (erc-cmd-JOIN "#chan"))
-
- (with-current-buffer erc-serv-buf-b
- (should (string= (buffer-name) serv-buf-b))
- (funcall expect 3 "debug mode")
- (erc-cmd-JOIN "#chan"))
-
- (erc-d-t-wait-for 10 (get-buffer chan-buf-a))
- (erc-d-t-wait-for 10 (get-buffer chan-buf-b))
-
- (ert-info ("Greets other nick in same channel")
- (with-current-buffer chan-buf-a
- (funcall expect 5 "chester")
- (funcall expect 5 "find the forester")
- (erc-cmd-MSG "#chan chester: hi")))
-
- (ert-info ("Sees other nick in same channel")
- (with-current-buffer chan-buf-b
- (funcall expect 5 "tester")
- (funcall expect 10 "<tester> chester: hi")
- (funcall expect 5 "This was lofty")
- (erc-cmd-MSG "#chan hi tester")))
-
- (with-current-buffer chan-buf-a
- (funcall expect 5 "To employ you towards")
- (erc-cmd-QUIT ""))
-
- (with-current-buffer chan-buf-b
- (funcall expect 5 "To employ you towards")
- (erc-cmd-QUIT ""))))
-
-(ert-deftest erc-scenarios-base-network-id-same-network--two-ids ()
- (erc-scenarios-common--base-network-id-same-network
- (list :nick "tester"
- :id 'tester/foonet
- :server "tester/foonet"
- :chan "#chan@tester/foonet")
- (list :nick "chester"
- :id 'chester/foonet
- :server "chester/foonet"
- :chan "#chan@chester/foonet")))
-
-(ert-deftest erc-scenarios-base-network-id-same-network--one-id-tester ()
- (erc-scenarios-common--base-network-id-same-network
- (list :nick "tester"
- :id 'tester/foonet
- :server "tester/foonet"
- :chan "#chan@tester/foonet")
- (list :nick "chester"
- :id nil
- :server "foonet"
- :chan "#chan@foonet")))
-
-(ert-deftest erc-scenarios-base-network-id-same-network--one-id-chester ()
- (erc-scenarios-common--base-network-id-same-network
- (list :nick "tester"
- :id nil
- :server "foonet"
- :chan "#chan@foonet")
- (list :nick "chester"
- :id 'chester/foonet
- :server "chester/foonet"
- :chan "#chan@chester/foonet")))
-
-(ert-deftest erc-scenarios-base-network-id-same-network--no-ids ()
- (erc-scenarios-common--base-network-id-same-network
- (list :nick "tester"
- :id nil
- :server "foonet/tester"
- :chan "#chan@foonet/tester") ; <- note net before nick
- (list :nick "chester"
- :id nil
- :server "foonet/chester"
- :chan "#chan@foonet/chester")))
-
-;; Upon reconnecting, playback for channel and target buffers is
-;; routed correctly. Autojoin is irrelevant here, but for the
-;; skeptical, see `erc-scenarios-common--join-network-id', which
-;; overlaps with this and includes spurious JOINs ignored by the
-;; server.
-
-(ert-deftest erc-scenarios-base-association-reconnect-playback ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/association/reconnect-playback")
- (erc-d-linger-secs 0.5)
- (erc-server-flood-penalty 0.1)
- (erc-server-flood-margin 30)
- (dumb-server (erc-d-run "localhost" t 'foonet 'foonet-again))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- erc-autojoin-channels-alist
- erc-server-buffer-foo)
-
- (ert-info ("Connect to foonet")
- (setq erc-server-buffer-foo (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester"))
- (with-current-buffer erc-server-buffer-foo
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (ert-info ("Setup")
-
- (ert-info ("Server buffer is unique and temp name is absent")
- (erc-d-t-wait-for 1 (get-buffer "foonet"))
- (should-not (erc-scenarios-common-buflist "127.0.0.1")))
-
- (ert-info ("Channel buffer #chan playback received")
- (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#chan"))
- (funcall expect 10 "But purgatory")))
-
- (ert-info ("Ask for help from services or bouncer bot")
- (with-current-buffer erc-server-buffer-foo
- (erc-cmd-MSG "*status help")))
-
- (ert-info ("Help received")
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "*status"))
- (funcall expect 10 "Rehash")))
-
- (ert-info ("#chan convo done")
- (with-current-buffer "#chan"
- (funcall expect 10 "most egregious indignity"))))
-
- ;; KLUDGE (see note above test)
- (should erc-autojoin-channels-alist)
- (setq erc-autojoin-channels-alist nil)
-
- (with-current-buffer erc-server-buffer-foo
- (erc-cmd-QUIT "")
- (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
- (erc-cmd-RECONNECT))
-
- (ert-info ("Channel buffer found and associated")
- (with-current-buffer "#chan"
- (funcall expect 10 "Wilt thou rest damned")))
-
- (ert-info ("Help buffer found and associated")
- (with-current-buffer "*status"
- (goto-char erc-input-marker)
- (insert "help")
- (erc-send-current-line)
- (funcall expect 10 "Restart ZNC")))
-
- (ert-info ("#chan convo done")
- (with-current-buffer "#chan"
- (funcall expect 10 "here comes the lady")))))
-
-;; You register a new nick, disconnect, and log back in, but your nick
-;; is not granted, so ERC obtains a backtick'd version. You open a
-;; query buffer for NickServ, and ERC names it using the session ID
-;; (which includes the backtick'd nick) as a suffix. The original
-;; (disconnected) NickServ buffer gets renamed with *its* session ID
-;; as well. You then identify to NickServ, and the dead session is no
-;; longer considered distinct.
-
-(ert-deftest erc-scenarios-base-association-nick-bumped ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/association/nick-bump")
- (dumb-server (erc-d-run "localhost" t 'renicked 'renicked-again))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-flood-penalty 0.5)
- (erc-server-flood-margin 30))
-
- (ert-info ("Connect to foonet with nick tester")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :full-name "tester")
- (erc-scenarios-common-assert-initial-buf-name nil port)
- (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
-
- (ert-info ("Create an account for tester and quit")
- (with-current-buffer "foonet"
- (funcall expect 3 "debug mode")
-
- (erc-cmd-QUERY "NickServ")
- (with-current-buffer "NickServ"
- (erc-send-input-line "NickServ" "REGISTER changeme")
- (funcall expect 5 "Account created")
- (funcall expect 1 "You're now logged in as tester"))
-
- (with-current-buffer "foonet"
- (erc-cmd-QUIT "")
- (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
- (funcall expect 5 "ERC finished"))))
-
- (with-current-buffer "foonet"
- (erc-cmd-RECONNECT))
-
- (erc-d-t-wait-for 10 "Nick request rejection prevents reassociation (good)"
- (get-buffer "foonet/tester`"))
-
- (ert-info ("Ask NickServ to change nick")
- (with-current-buffer "foonet/tester`"
- (funcall expect 3 "already in use")
- (funcall expect 3 "debug mode")
- (erc-cmd-QUERY "NickServ"))
-
- (erc-d-t-wait-for 1 "Dead NickServ query buffer renamed, now qualified"
- (get-buffer "NickServ@foonet/tester"))
-
- (with-current-buffer "NickServ@foonet/tester`" ; new one
- (erc-send-input-line "NickServ" "IDENTIFY tester changeme")
- (funcall expect 5 "You're now logged in as tester")
- (ert-info ("Original buffer found, reused")
- (erc-d-t-wait-for 2 (equal (buffer-name) "NickServ")))))
-
- (ert-info ("Ours is the only NickServ buffer that remains")
- (should-not (cdr (erc-scenarios-common-buflist "NickServ"))))
-
- (ert-info ("Visible network ID truncated to one component")
- (should (not (get-buffer "foonet/tester`")))
- (should (not (get-buffer "foonet/tester")))
- (should (get-buffer "foonet")))))
-
-;; A less common variant is when your bouncer switches to an alternate
-;; nick while you're disconnected, and upon reconnecting, you get
-;; a new nick.
-
-(ert-deftest erc-scenarios-base-association-nick-bumped-mandated-renick ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/association/nick-bump")
- (dumb-server (erc-d-run "localhost" t
- 'renicked-foisted 'renicked-foisted-again))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter))
- (erc-server-flood-penalty 0.5)
- (erc-server-flood-margin 30))
-
- (ert-info ("Connect to foonet with nick tester")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :full-name "tester")
- (erc-scenarios-common-assert-initial-buf-name nil port)
- (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
-
- (ert-info ("Greet bob and quit")
- (with-current-buffer "foonet"
- (funcall expect 3 "debug mode")
-
- (erc-cmd-QUERY "bob")
- (with-current-buffer "bob"
- (erc-send-input-line "bob" "hi")
- (funcall expect 5 "hola")
- (funcall expect 1 "how r u?"))
-
- (with-current-buffer "foonet"
- (erc-cmd-QUIT "")
- (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
- (funcall expect 5 "ERC finished"))))
-
- ;; Since we use reconnect, a new buffer won't be created
- ;; TODO add variant with clean `erc' invocation
- (with-current-buffer "foonet"
- (erc-cmd-RECONNECT))
-
- (ert-info ("Server-initiated renick")
- (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet/dummy"))
- (should-not (get-buffer "foonet/tester"))
- (funcall expect 5 "debug mode"))
-
- (erc-d-t-wait-for 1 "Old query renamed, now qualified"
- (get-buffer "bob@foonet/tester"))
-
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "bob@foonet/dummy"))
- (erc-cmd-NICK "tester")
- (ert-info ("Buffers combined")
- (erc-d-t-wait-for 2 (equal (buffer-name) "bob")))))
-
- (with-current-buffer "foonet"
- (funcall expect 5 "You're now logged in as tester"))
-
- (ert-info ("Ours is the only bob buffer that remains")
- (should-not (cdr (erc-scenarios-common-buflist "bob"))))
-
- (ert-info ("Visible network ID truncated to one component")
- (should (not (get-buffer "foonet/dummy")))
- (should (get-buffer "foonet")))))
-
-;; Auth source consulted for initial PASS arg. Option
-;; `erc-connect-auth-source-host' obeyed.
-
-(defun erc-scenarios-common--auth-source (id dialog &rest rest)
- (push "machine GNU.chat port %d user \"#chan\" password spam" rest)
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/auth-source")
- (dumb-server (erc-d-run "localhost" t dialog))
- (port (process-contact dumb-server :service))
- (ents `(,@(mapcar (lambda (fmt) (format fmt port)) rest)
- "machine MyHost port irc password 123"))
- (netrc-file (make-temp-file "auth-source-test" nil nil
- (string-join ents "\n")))
- (auth-sources (list netrc-file))
- (auth-source-do-cache nil)
- (erc-scenarios-common-extra-teardown (lambda ()
- (delete-file netrc-file))))
-
- (ert-info ("Connect")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :full-name "tester"
- :id id)
- (should (string= (buffer-name) (if id
- (symbol-name id)
- (format "127.0.0.1:%d" port))))
- (erc-d-t-wait-for 1 (eq erc-network 'FooNet))))))
-
-(ert-deftest erc-scenarios-base-auth-source--dialed ()
- (should (eq erc-connect-auth-source-host 'server))
- (erc-scenarios-common--auth-source
- nil 'foonet
- "machine GNU.chat port %d user tester password fake"
- "machine 127.0.0.1 port %d user tester password changeme"
- "machine 127.0.0.1 port %d user imposter password fake"))
-
-(ert-deftest erc-scenarios-base-auth-source--dialed-fallback ()
- (let ((erc-connect-auth-source-host t))
- (erc-scenarios-common--auth-source
- nil 'foonet
- "machine FooNet port %d user tester password fake"
- "machine 127.0.0.1 port %d user tester password changeme"
- "machine 127.0.0.1 port %d user imposter password fake")))
-
-(ert-deftest erc-scenarios-base-auth-source--network-id ()
- (let ((erc-connect-auth-source-host t))
- (erc-scenarios-common--auth-source
- 'MySession 'foonet
- "machine MySession port %d user tester password changeme"
- "machine 127.0.0.1 port %d user tester password fake"
- "machine FooNet port %d user tester password fake")))
-
-(ert-deftest erc-scenarios-base-auth-source--string--network-id ()
- (let ((erc-connect-auth-source-host "MyHost"))
- (erc-scenarios-common--auth-source
- 'MySession 'foonet
- "machine 127.0.0.1 port %d user tester password fake"
- "machine MyHost port %d user tester password changeme"
- "machine MySession port %d user tester password fake")))
-
-(ert-deftest erc-scenarios-base-auth-source--nopass ()
- (let (erc-connect-auth-source-host) ; nil
- (erc-scenarios-common--auth-source nil 'nopass)))
-
-(ert-deftest erc-scenarios-base-auth-source--nopass--network-id ()
- (let (erc-connect-auth-source-host) ; nil
- (erc-scenarios-common--auth-source 'MySession 'nopass)))
-
-;; Identify via auth source with no initial password
-
-(defun erc-scenarios-common--services-auth-source (&rest rest)
- (defvar erc-use-auth-source-for-nickserv-password)
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "services/auth-source")
- (erc-server-flood-penalty 0.1)
- (dumb-server (erc-d-run "localhost" t 'libera))
- (port (process-contact dumb-server :service))
- (ents `(,@(mapcar (lambda (fmt) (format fmt port)) rest)
- "machine MyHost port irc password 123"))
- (netrc-file (make-temp-file "auth-source-test" nil nil
- (string-join ents "\n")))
- (auth-sources (list netrc-file))
- (auth-source-do-cache nil)
- (erc-modules (cons 'services erc-modules))
- (erc-use-auth-source-for-nickserv-password t) ; do consult for NickServ
- (expect (erc-d-t-make-expecter))
- (erc-scenarios-common-extra-teardown (lambda ()
- (delete-file netrc-file))))
-
- (cl-letf (((symbol-function 'read-passwd)
- (lambda (&rest _) (error "Unexpected read-passwd call"))))
- (ert-info ("Connect without password")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (erc-d-t-wait-for 3 (eq erc-network 'Libera.Chat))
- (funcall expect 3 "This nickname is registered.")
- (funcall expect 3 "You are now identified")
- (funcall expect 3 "Last login from")
- (erc-cmd-QUIT ""))))
-
- (erc-services-mode -1)
-
- (should-not (memq 'services erc-modules))))
-
-(ert-deftest erc-scenarios-services-auth-source--network ()
- (let (erc-connect-auth-source-host) ; don't consult auth-source for PASS
- (erc-scenarios-common--services-auth-source
- "machine 127.0.0.1 port %d user tester password spam"
- "machine zirconium.libera.chat port %d user tester password fake"
- "machine Libera.Chat port %d user tester password changeme")))
-
-(ert-deftest erc-scenarios-services-auth-source--network-connect-lookup ()
- (should (eq erc-connect-auth-source-host 'server))
- (erc-scenarios-common--services-auth-source
- "machine zirconium.libera.chat port %d user tester password fake"
- "machine Libera.Chat port %d user tester password changeme"))
-
-(ert-deftest erc-scenarios-services-auth-source--announced ()
- (let (erc-connect-auth-source-host) ; don't consult auth-source for PASS
- (erc-scenarios-common--services-auth-source
- "machine 127.0.0.1 port %d user tester password spam"
- "machine zirconium.libera.chat port %d user tester password changeme")))
-
-(ert-deftest erc-scenarios-services-auth-source--dialed ()
- (let (erc-connect-auth-source-host) ; don't consult auth-source for PASS
- (erc-scenarios-common--services-auth-source
- "machine 127.0.0.1 port %d user tester password changeme")))
-
-(ert-deftest erc-scenarios-services-password ()
-
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "services/password")
- (erc-server-flood-penalty 0.1)
- (erc-modules (cons 'services erc-modules))
- (erc-nickserv-passwords '((Libera.Chat (("joe" . "bar")
- ("tester" . "changeme")))))
- (expect (erc-d-t-make-expecter))
- (dumb-server (erc-d-run "localhost" t 'libera))
- (port (process-contact dumb-server :service)))
-
- (ert-info ("Connect without password")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (erc-d-t-wait-for 2 (eq erc-network 'Libera.Chat))
- (funcall expect 1 "This nickname is registered.")
- (funcall expect 1 "You are now identified")
- (funcall expect 1 "Last login from")
- (erc-cmd-QUIT "")))
-
- (erc-services-mode -1)
-
- (should-not (memq 'services erc-modules))))
-
-(ert-deftest erc-scenarios-services-prompt ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "services/password")
- (erc-server-flood-penalty 0.1)
- (inhibit-interaction nil)
- (erc-modules (cons 'services erc-modules))
- (expect (erc-d-t-make-expecter))
- (dumb-server (erc-d-run "localhost" t 'libera))
- (port (process-contact dumb-server :service)))
-
- (ert-info ("Connect without password")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (ert-simulate-keys "changeme\r"
- (erc-d-t-wait-for 2 (eq erc-network 'Libera.Chat))
- (funcall expect 3 "This nickname is registered.")
- (funcall expect 3 "You are now identified")
- (funcall expect 3 "Last login from"))
- (erc-cmd-QUIT "")))
-
- (erc-services-mode -1)
-
- (should-not (memq 'services erc-modules))))
-
-(ert-deftest erc-scenarios-base-flood ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/flood")
- (erc-d-linger-secs 0.5)
- (dumb-server (erc-d-run "localhost" t 'soju))
- (port (process-contact dumb-server :service))
- (erc-server-flood-penalty 0.5) ; this ratio MUST match
- (erc-server-flood-margin 1.5) ; the default of 3:10
- (expect (erc-d-t-make-expecter))
- erc-autojoin-channels-alist)
-
- (ert-info ("Connect to bouncer")
- (with-current-buffer
- (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (funcall expect 5 "Soju")))
-
- (ert-info ("#chan@foonet exists")
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/foonet"))
- (erc-d-t-search-for 2 "<bob/foonet>")
- (erc-d-t-absent-for 0.1 "<joe")
- (funcall expect 3 "was created on")))
-
- (ert-info ("#chan@barnet exists")
- (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/barnet"))
- (erc-d-t-search-for 2 "<joe/barnet>")
- (erc-d-t-absent-for 0.1 "<bob")
- (funcall expect 3 "was created on")
- (funcall expect 5 "To get good guard")))
-
- (ert-info ("Message not held in queue limbo")
- (with-current-buffer "#chan/foonet"
- ;; Without 'no-penalty param in `erc-server-send', should fail
- ;; after ~10 secs with:
- ;;
- ;; (erc-d-timeout "Timed out awaiting request: (:name ~privmsg
- ;; :pattern \\`PRIVMSG #chan/foonet :alice: hi :timeout 2
- ;; :dialog soju)")
- ;;
- ;; Try reversing commit and spying on queue interactively
- (erc-cmd-MSG "#chan/foonet alice: hi")
- (funcall expect 5 "tester: Good, very good")))
-
- (ert-info ("All output sent")
- (with-current-buffer "#chan/foonet"
- (funcall expect 5 "Some man or other"))
- (with-current-buffer "#chan/barnet"
- (while (accept-process-output erc-server-process))
- (funcall expect 5 "That's he that was Othello")))))
-
-;; Corner case demoing fallback behavior for an absent 004 RPL but a
-;; present 422 or 375. If this is unlikely enough, remove or guard
-;; with `ert-skip' plus some condition so it only runs when explicitly
-;; named via ERT specifier
-
-(ert-deftest erc-scenarios-networks-announced-missing ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "networks/announced-missing")
- (erc-d-linger-secs 0.5)
- (expect (erc-d-t-make-expecter))
- (dumb-server (erc-d-run "localhost" t 'foonet))
- (port (process-contact dumb-server :service)))
-
- (ert-info ("Connect without password")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
- (let ((err (should-error (sleep-for 1))))
- (should (string-match-p "Failed to determine" (cadr err))))
- (funcall expect 1 "Failed to determine")
- (funcall expect 1 "Failed to determine")
- (should-not erc-network)
- (should (string= erc-server-announced-name "irc.foonet.org"))))))
-
-;; Targets that are host/server masks like $*, $$*, and #* are routed
-;; to the server buffer: https://github.com/ircdocs/wooooms/issues/5
-
-(ert-deftest erc-scenarios-base-mask-target-routing ()
- (erc-scenarios-common-with-cleanup
- ((erc-scenarios-common-dialog "base/mask-target-routing")
- (erc-d-linger-secs 0.5)
- (dumb-server (erc-d-run "localhost" t 'foonet))
- (port (process-contact dumb-server :service))
- (expect (erc-d-t-make-expecter)))
-
- (ert-info ("Connect to foonet")
- (with-current-buffer (erc :server "127.0.0.1"
- :port port
- :nick "tester"
- :password "changeme"
- :full-name "tester")
- (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
-
- (erc-d-t-wait-for 1 (get-buffer "foonet"))
-
- (ert-info ("Channel buffer #foo playback received")
- (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#foo"))
- (funcall expect 10 "Excellent workman")))
-
- (ert-info ("Global notices routed to server buffer")
- (with-current-buffer "foonet"
- (funcall expect 10 "going down soon")
- (funcall expect 10 "this is a warning")
- (funcall expect 10 "second warning")
- (funcall expect 10 "final warning")))
-
- (should-not (get-buffer "$*"))))
-
-;;; erc-scenarios.el ends here
diff --git a/test/lisp/erc/erc-d/erc-d-self.el
b/test/lisp/erc/erc-scenarios/erc-d-self.el
similarity index 95%
rename from test/lisp/erc/erc-d/erc-d-self.el
rename to test/lisp/erc/erc-scenarios/erc-d-self.el
index c5b8f15cb2..c6e6d33bd2 100644
--- a/test/lisp/erc/erc-d/erc-d-self.el
+++ b/test/lisp/erc/erc-scenarios/erc-d-self.el
@@ -1,5 +1,7 @@
;;; erc-d-self.el --- tests for erc-d -*- lexical-binding: t -*-
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+;;
;; This file is part of GNU Emacs.
;;
;; This program is free software: you can redistribute it and/or
@@ -24,14 +26,22 @@
;;; Code:
(require 'ert-x)
-(eval-and-compile (let ((dir (getenv "EMACS_TEST_DIRECTORY")))
- (when dir
- (load (concat dir "/lisp/erc/erc-d/erc-d") nil t)
- (load (concat dir "/lisp/erc/erc-d/erc-d-t") nil t))))
+(eval-and-compile
+ (let ((load-path (cons (expand-file-name "erc-d" (ert-resource-directory))
+ load-path)))
+ (require 'erc-d)
+ (require 'erc-d-t)))
+
+(require 'erc)
+
+;; For now, we need these tests to work in two different layouts:
+;; inside emacs.git, under test/lisp/erc/erc-scenarios, and as part of
+;; a standalone erc-d library.
-(require 'erc-d)
-(require 'erc-d-t)
-(require 'erc-backend)
+(defvar erc-d-self--resources-directory
+ (let ((default-directory (ert-resource-directory)))
+ (expand-file-name
+ (if (file-readable-p "erc-d/resources") "erc-d/resources" ""))))
(ert-deftest erc-d-u--canned-load-dialog--basic ()
(should-not (get-buffer "basic.eld"))
@@ -281,7 +291,8 @@
(ert-deftest erc-d-i--parse-message--irc-parser-tests ()
(let* ((data (with-temp-buffer
(insert-file-contents
- (ert-resource-file "irc-parser-tests.eld"))
+ (expand-file-name "irc-parser-tests.eld"
+ erc-d-self--resources-directory))
(read (current-buffer))))
(tests (assoc-default 'tests (assoc-default 'msg-split data)))
input atoms m ours)
@@ -524,6 +535,17 @@
(should (get-buffer "*foo*"))
(kill-buffer "*foo*")))
+(ert-deftest erc-d-t-wait-for ()
+ (let (v)
+ (run-at-time 0.2 nil (lambda () (setq v t)))
+ (should (erc-d-t-wait-for 0.4 "result becomes non-nil" v))
+ (should-error (erc-d-t-wait-for 0.4 "result stays nil" (not v)))
+ (setq v nil)
+ (should-not (erc-d-t-wait-for -0.4 "inverted stays nil" v))
+ (run-at-time 0.2 nil (lambda () (setq v t)))
+ (setq v nil)
+ (should-error (erc-d-t-wait-for -0.4 "inverted becomes non-nil" v))))
+
(defvar erc-d-self-with-server-password "changeme")
;; Compromise between removing `autojoin' from `erc-modules' entirely
@@ -581,22 +603,22 @@ DUMB-SERVER-VAR are bound accordingly in BODY."
"Wrap functions with advice for inspecting errors caused by BODY.
Do this for functions whose names appear in FUNC-SYMS. When running
advice code, add errors to list FOUND. Note: the teardown finalizer is
-not added by default. Also, `erc-d-linger-secs' likely has to
-be nonzero for this to work."
+not added by default. Also, `erc-d-linger-secs' likely has to be
+nonzero for this to work."
(declare (indent 2))
;; Catch errors thrown by timers that `should-error'ignores
`(progn
- (cl-labels ((ad (f o &rest r)
- (condition-case err
- (apply o r)
- (error (push err ,found)
- (advice-remove f 'spy)))))
+ (let ((ad (lambda (f o &rest r)
+ (condition-case err
+ (apply o r)
+ (error (push err ,found)
+ (advice-remove f 'spy))))))
(dolist (sym ,func-syms)
- (advice-add sym :around (apply-partially #'ad sym) '((name . spy))))
- (progn ,@body))
- (setq ,found (nreverse ,found))
+ (advice-add sym :around (apply-partially ad sym) '((name . spy)))))
+ (progn ,@body)
(dolist (sym ,func-syms)
- (advice-remove sym 'spy))))
+ (advice-remove sym 'spy))
+ (setq ,found (nreverse ,found))))
(ert-deftest erc-d-run-nonstandard-messages ()
(let* ((erc-d-linger-secs 0.2)
@@ -827,7 +849,7 @@ be nonzero for this to work."
(defun erc-d-self--run-dynamic ()
"Perform common assertions for \"dynamic\" dialog."
(erc-d-self-with-server (dumb-server erc-server-buffer) dynamic
- (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#chan"))
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
(erc-d-t-search-for 2 "tester: hey"))
(with-current-buffer erc-server-buffer
(let ((expect (erc-d-t-make-expecter)))
@@ -840,7 +862,7 @@ be nonzero for this to work."
(ert-deftest erc-d-run-dynamic-default-match ()
(let* (dynamic-tally
- (erc-d-spec-vars '((user . "user")
+ (erc-d-tmpl-vars '((user . "user")
(ignored . ((a b) (: a space b)))
(realname . (group (+ graph)))))
(nick (lambda (a)
@@ -865,7 +887,7 @@ be nonzero for this to work."
(ert-deftest erc-d-run-dynamic-default-match-rebind ()
(let* (tally
;;
- (erc-d-spec-vars '((user . "user")
+ (erc-d-tmpl-vars '((user . "user")
(ignored . ((a b) (: a space b)))
(realname . (group (+ graph)))))
(erc-d-match-handlers
@@ -891,7 +913,7 @@ be nonzero for this to work."
(should (equal '(bind-nick bind-dom) tally))))
(ert-deftest erc-d-run-dynamic-runtime-stub ()
- (let ((erc-d-spec-vars '((token . (group (or "barnet" "foonet")))))
+ (let ((erc-d-tmpl-vars '((token . (group (or "barnet" "foonet")))))
(erc-d-match-handlers
(list :pass (lambda (d _e)
(erc-d-load-replacement-dialog d 'dynamic-foonet))))
@@ -909,7 +931,7 @@ be nonzero for this to work."
(kill-buffer "#chan")))))
(ert-deftest erc-d-run-dynamic-runtime-stub-skip ()
- (let ((erc-d-spec-vars '((token . "barnet")))
+ (let ((erc-d-tmpl-vars '((token . "barnet")))
(erc-d-match-handlers
(list :pass (lambda (d _e)
(erc-d-load-replacement-dialog
@@ -978,7 +1000,7 @@ be nonzero for this to work."
;; This can be removed; only exists to get a baseline for next test
(ert-deftest erc-d-run-fuzzy-direct ()
- (let* ((erc-d-spec-vars
+ (let* ((erc-d-tmpl-vars
`((now . ,(lambda () (format-time-string "%FT%T.%3NZ" nil t)))))
(dumb-server (erc-d-run "localhost" t 'fuzzy))
(dumb-server-buffer (get-buffer "*erc-d-server*"))
@@ -1020,7 +1042,7 @@ be nonzero for this to work."
(ert-deftest erc-d-run-fuzzy ()
(let ((erc-server-flood-penalty 1.2) ; penalty < margin/sends is basically 0
(erc-d-linger-secs 0.1)
- (erc-d-spec-vars
+ (erc-d-tmpl-vars
`((now . ,(lambda () (format-time-string "%FT%T.%3NZ" nil t)))))
erc-server-auto-reconnect)
(erc-d-self-with-server (_ erc-server-buffer) fuzzy
@@ -1057,8 +1079,8 @@ be nonzero for this to work."
(with-current-buffer "#bar" (funcall expect 1 "was created on"))
(ert-info ("Server expects next pattern but keeps sending")
- (with-current-buffer "#foo" (funcall expect 2 "Rosalind"))
- (with-current-buffer "#bar" (funcall expect 1 "hi"))
+ (with-current-buffer "#foo" (funcall expect 2 "Rosalind, I will "))
+ (with-current-buffer "#bar" (funcall expect 1 "hi 123"))
(with-current-buffer "#foo"
(should-not (search-forward "<bob> I am heard" nil t))
(funcall expect 1.5 "<bob> I am heard"))))))
@@ -1125,13 +1147,13 @@ bouncer-like setup."
(kill-buffer dumb-server-buffer))))
;; This test shows the simplest way to set up template variables: put
-;; everything needed for the whole session in `erc-d-spec-vars' before
+;; everything needed for the whole session in `erc-d-tmpl-vars' before
;; starting the server.
(ert-deftest erc-d-run-proxy-direct-spec-vars ()
(let* ((dumb-server-buffer (get-buffer-create "*erc-d-server*"))
(erc-d-linger-secs 0.5)
- (erc-d-spec-vars
+ (erc-d-tmpl-vars
`((network . (group (+ alpha)))
(fqdn . ,(lambda (a)
(let ((network (funcall a :match 1 'pass)))
@@ -1183,7 +1205,7 @@ DIALOGS are symbols representing the base names of dialog
files in
(if (eq (funcall a :dialog-name) 'proxy-foonet)
"FooNet"
"BarNet"))))
- (program `(setq erc-d-spec-vars '((fqdn . ,fqdn)
+ (program `(setq erc-d-tmpl-vars '((fqdn . ,fqdn)
(net . ,net)
(network . (group (+ alpha))))))
(port (erc-d-self--start-server
@@ -1196,7 +1218,8 @@ DIALOGS are symbols representing the base names of dialog
files in
(ert-deftest erc-d-run-proxy-direct-subprocess-lib ()
(let* ((buffer (get-buffer-create "*erc-d-server*"))
- (lib (ert-resource-file "proxy-subprocess.el"))
+ (lib (expand-file-name "proxy-subprocess.el"
+ erc-d-self--resources-directory))
(port (erc-d-self--start-server :linger 0.3
:buffer buffer
:dialogs '(proxy-foonet proxy-barnet)
@@ -1207,7 +1230,7 @@ DIALOGS are symbols representing the base names of dialog
files in
(ert-deftest erc-d-run-no-pong ()
(let* (erc-d-auto-pong
;;
- (erc-d-spec-vars
+ (erc-d-tmpl-vars
`((nonce . (group (: digit digit)))
(echo . ,(lambda (a)
(should (string= (funcall a :match 1) "42")) "42"))))
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-auth-source.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-auth-source.el
new file mode 100644
index 0000000000..bb8d7ecad3
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-auth-source.el
@@ -0,0 +1,178 @@
+;;; erc-scenarios-auth-source.el --- auth-source scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+;; Commentary:
+;;
+;; For practical reasons (mainly lack of imagination), this file
+;; contains tests for both server-password and NickServ contexts.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join)
+ (require 'erc-services))
+
+(defun erc-scenarios-common--auth-source (id dialog &rest rest)
+ (push "machine GNU.chat port %d user \"#chan\" password spam" rest)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/auth-source")
+ (dumb-server (erc-d-run "localhost" t dialog))
+ (port (process-contact dumb-server :service))
+ (ents `(,@(mapcar (lambda (fmt) (format fmt port)) rest)
+ "machine MyHost port irc password 123"))
+ (netrc-file (make-temp-file "auth-source-test" nil nil
+ (string-join ents "\n")))
+ (auth-sources (list netrc-file))
+ (auth-source-do-cache nil)
+ (erc-scenarios-common-extra-teardown (lambda ()
+ (delete-file netrc-file))))
+
+ (ert-info ("Connect")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :full-name "tester"
+ :id id)
+ (should (string= (buffer-name) (if id
+ (symbol-name id)
+ (format "127.0.0.1:%d" port))))
+ (erc-d-t-wait-for 5 (eq erc-network 'FooNet))))))
+
+(ert-deftest erc-scenarios-base-auth-source-server--dialed ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--auth-source
+ nil 'foonet
+ "machine GNU.chat port %d user tester password fake"
+ "machine FooNet port %d user tester password fake"
+ "machine 127.0.0.1 port %d user tester password changeme"
+ "machine 127.0.0.1 port %d user imposter password fake"))
+
+(ert-deftest erc-scenarios-base-auth-source-server--netid ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--auth-source
+ 'MySession 'foonet
+ "machine MySession port %d user tester password changeme"
+ "machine 127.0.0.1 port %d user tester password fake"
+ "machine FooNet port %d user tester password fake"))
+
+(ert-deftest erc-scenarios-base-auth-source-server--netid-custom ()
+ :tags '(:expensive-test)
+ (let ((erc-auth-source-parameters-server-function
+ (lambda (&rest _) (list :host "MyHost"))))
+ (erc-scenarios-common--auth-source
+ 'MySession 'foonet
+ "machine 127.0.0.1 port %d user tester password fake"
+ "machine MyHost port %d user tester password changeme"
+ "machine MySession port %d user tester password fake")))
+
+(ert-deftest erc-scenarios-base-auth-source-server--nopass ()
+ :tags '(:expensive-test)
+ (let (erc-auth-source-parameters-server-function)
+ (erc-scenarios-common--auth-source nil 'nopass)))
+
+(ert-deftest erc-scenarios-base-auth-source-server--nopass-netid ()
+ :tags '(:expensive-test)
+ (let (erc-auth-source-parameters-server-function)
+ (erc-scenarios-common--auth-source 'MySession 'nopass)))
+
+;; Identify via auth source with no initial password
+
+(defun erc-scenarios-common--services-auth-source (&rest rest)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "services/auth-source")
+ (erc-server-flood-penalty 0.1)
+ (dumb-server (erc-d-run "localhost" t 'libera))
+ (port (process-contact dumb-server :service))
+ (ents `(,@(mapcar (lambda (fmt) (format fmt port)) rest)
+ "machine MyHost port irc password 123"))
+ (netrc-file (make-temp-file "auth-source-test" nil nil
+ (string-join ents "\n")))
+ (auth-sources (list netrc-file))
+ (auth-source-do-cache nil)
+ (erc-modules (cons 'services erc-modules))
+ (erc-use-auth-source-for-nickserv-password t) ; do consult for NickServ
+ (expect (erc-d-t-make-expecter))
+ (erc-scenarios-common-extra-teardown (lambda ()
+ (delete-file netrc-file))))
+
+ (cl-letf (((symbol-function 'read-passwd)
+ (lambda (&rest _) (error "Unexpected read-passwd call"))))
+ (ert-info ("Connect without password")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (erc-d-t-wait-for 8 (eq erc-network 'Libera.Chat))
+ (funcall expect 3 "This nickname is registered.")
+ (funcall expect 3 "You are now identified")
+ (funcall expect 3 "Last login from")
+ (erc-cmd-QUIT ""))))
+
+ (erc-services-mode -1)
+
+ (should-not (memq 'services erc-modules))))
+
+;; These tests are about authenticating to nick services
+
+(ert-deftest erc-scenarios-services-auth-source--network ()
+ :tags '(:expensive-test)
+ ;; Skip consulting auth-source for the server password (PASS).
+ (let (erc-auth-source-parameters-server-function)
+ (erc-scenarios-common--services-auth-source
+ "machine 127.0.0.1 port %d user tester password spam"
+ "machine zirconium.libera.chat port %d user tester password fake"
+ "machine Libera.Chat port %d user tester password changeme")))
+
+(ert-deftest erc-scenarios-services-auth-source--network-connect-lookup ()
+ :tags '(:expensive-test)
+ ;; Do consult auth-source for the server password (and find nothing)
+ (erc-scenarios-common--services-auth-source
+ "machine zirconium.libera.chat port %d user tester password fake"
+ "machine Libera.Chat port %d user tester password changeme"))
+
+(ert-deftest erc-scenarios-services-auth-source--announced ()
+ :tags '(:expensive-test)
+ (let (erc-auth-source-parameters-server-function)
+ (erc-scenarios-common--services-auth-source
+ "machine 127.0.0.1 port %d user tester password spam"
+ "machine zirconium.libera.chat port %d user tester password changeme")))
+
+(ert-deftest erc-scenarios-services-auth-source--dialed ()
+ :tags '(:expensive-test)
+ ;; Support legacy host -> domain name
+ ;; (likely most common in real configs)
+ (let (erc-auth-source-parameters-server-function)
+ (erc-scenarios-common--services-auth-source
+ "machine 127.0.0.1 port %d user tester password changeme")))
+
+(ert-deftest erc-scenarios-services-auth-source--custom ()
+ :tags '(:expensive-test)
+ (let (erc-auth-source-parameters-server-function
+ (erc-auth-source-parameters-services-function
+ (lambda (&rest _) '(:host "MyAccount"))))
+ (erc-scenarios-common--services-auth-source
+ "machine zirconium.libera.chat port %d user tester password spam"
+ "machine MyAccount port %d user tester password changeme"
+ "machine 127.0.0.1 port %d user tester password fake")))
+
+;;; erc-scenarios-auth-source.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-association-nick.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-association-nick.el
new file mode 100644
index 0000000000..3152542ecf
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-association-nick.el
@@ -0,0 +1,164 @@
+;;; erc-scenarios-base-association-nick.el --- base assoc scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; You register a new nick, disconnect, and log back in, but your nick
+;; is not granted, so ERC obtains a backtick'd version. You open a
+;; query buffer for NickServ, and ERC names it using the session ID
+;; (which includes the backtick'd nick) as a suffix. The original
+;; (disconnected) NickServ buffer gets renamed with *its* session ID
+;; as well. You then identify to NickServ, and the dead session is no
+;; longer considered distinct.
+
+(ert-deftest erc-scenarios-base-association-nick-bumped ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/association/nick-bump")
+ (dumb-server (erc-d-run "localhost" t 'renicked 'renicked-again))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-flood-penalty 0.5)
+ (erc-server-flood-margin 30))
+
+ (ert-info ("Connect to foonet with nick tester")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :full-name "tester")
+ (erc-scenarios-common-assert-initial-buf-name nil port)
+ (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+ (ert-info ("Create an account for tester and quit")
+ (with-current-buffer "foonet"
+ (funcall expect 3 "debug mode")
+
+ (erc-cmd-QUERY "NickServ")
+ (with-current-buffer "NickServ"
+ (erc-scenarios-common-say "REGISTER changeme")
+ (funcall expect 5 "Account created")
+ (funcall expect 1 "You're now logged in as tester"))
+
+ (with-current-buffer "foonet"
+ (erc-cmd-QUIT "")
+ (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+ (funcall expect 5 "ERC finished"))))
+
+ (with-current-buffer "foonet"
+ (erc-cmd-RECONNECT))
+
+ (erc-d-t-wait-for 10 "Nick request rejection prevents reassociation (good)"
+ (get-buffer "foonet/tester`"))
+
+ (ert-info ("Ask NickServ to change nick")
+ (with-current-buffer "foonet/tester`"
+ (funcall expect 3 "already in use")
+ (funcall expect 3 "debug mode")
+ (erc-cmd-QUERY "NickServ"))
+
+ (erc-d-t-wait-for 1 "Dead NickServ query buffer renamed, now qualified"
+ (get-buffer "NickServ@foonet/tester"))
+
+ (with-current-buffer "NickServ@foonet/tester`" ; new one
+ (erc-scenarios-common-say "IDENTIFY tester changeme")
+ (funcall expect 5 "You're now logged in as tester")
+ (ert-info ("Original buffer found, reused")
+ (erc-d-t-wait-for 2 (equal (buffer-name) "NickServ")))))
+
+ (ert-info ("Ours is the only NickServ buffer that remains")
+ (should-not (cdr (erc-scenarios-common-buflist "NickServ"))))
+
+ (ert-info ("Visible network ID truncated to one component")
+ (should (not (get-buffer "foonet/tester`")))
+ (should (not (get-buffer "foonet/tester")))
+ (should (get-buffer "foonet")))))
+
+;; A less common variant is when your bouncer switches to an alternate
+;; nick while you're disconnected, and upon reconnecting, you get
+;; a new nick.
+
+(ert-deftest erc-scenarios-base-association-nick-bumped-mandated-renick ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/association/nick-bump")
+ (dumb-server (erc-d-run "localhost" t
+ 'renicked-foisted 'renicked-foisted-again))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-flood-penalty 0.5)
+ (erc-server-flood-margin 30))
+
+ (ert-info ("Connect to foonet with nick tester")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :full-name "tester")
+ (erc-scenarios-common-assert-initial-buf-name nil port)
+ (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+ (ert-info ("Greet bob and quit")
+ (with-current-buffer "foonet"
+ (funcall expect 3 "debug mode")
+
+ (erc-cmd-QUERY "bob")
+ (with-current-buffer "bob"
+ (erc-scenarios-common-say "hi")
+ (funcall expect 5 "hola")
+ (funcall expect 1 "how r u?"))
+
+ (with-current-buffer "foonet"
+ (erc-cmd-QUIT "")
+ (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+ (funcall expect 5 "ERC finished"))))
+
+ ;; Since we use reconnect, a new buffer won't be created
+ ;; TODO add variant with clean `erc' invocation
+ (with-current-buffer "foonet"
+ (erc-cmd-RECONNECT))
+
+ (ert-info ("Server-initiated renick")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet/dummy"))
+ (should-not (get-buffer "foonet/tester"))
+ (funcall expect 15 "debug mode"))
+
+ (erc-d-t-wait-for 1 "Old query renamed, now qualified"
+ (get-buffer "bob@foonet/tester"))
+
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "bob@foonet/dummy"))
+ (erc-cmd-NICK "tester")
+ (ert-info ("Buffers combined")
+ (erc-d-t-wait-for 2 (equal (buffer-name) "bob")))))
+
+ (with-current-buffer "foonet"
+ (funcall expect 5 "You're now logged in as tester"))
+
+ (ert-info ("Ours is the only bob buffer that remains")
+ (should-not (cdr (erc-scenarios-common-buflist "bob"))))
+
+ (ert-info ("Visible network ID truncated to one component")
+ (should (not (get-buffer "foonet/dummy")))
+ (should (get-buffer "foonet")))))
+
+;;; erc-scenarios-base-association-nick.el ends here
diff --git
a/test/lisp/erc/erc-scenarios/erc-scenarios-base-association-samenet.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-association-samenet.el
new file mode 100644
index 0000000000..d27495b584
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-association-samenet.el
@@ -0,0 +1,144 @@
+;;; erc-scenarios-base-association-samenet.el --- assoc samenet scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(declare-function erc-network-name "erc-networks")
+(declare-function erc-network "erc-networks")
+(defvar erc-autojoin-channels-alist)
+(defvar erc-network)
+
+;; One network, two simultaneous connections, no IDs.
+;; Reassociates on reconnect with and without server buffer.
+
+(defun erc-scenarios-common--base-association-samenet (after)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/association/same-network")
+ (dumb-server (erc-d-run "localhost" t 'tester 'chester 'tester-again))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-flood-penalty 0.5)
+ (erc-server-flood-margin 30))
+
+ (ert-info ("Connect to foonet with nick tester")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+ (erc-scenarios-common-assert-initial-buf-name nil port)
+ (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+ (ert-info ("Connect to foonet with nick chester")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "chester"
+ :password "changeme"
+ :full-name "chester")
+ (erc-scenarios-common-assert-initial-buf-name nil port)))
+
+ (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
+ (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+ (with-current-buffer "foonet/tester"
+ (funcall expect 3 "debug mode")
+ (erc-cmd-JOIN "#chan"))
+
+ (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
+ (with-current-buffer "foonet/chester" (funcall expect 3 "debug mode"))
+ (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
+
+ (ert-info ("Nick tester sees other nick chester in channel")
+ (with-current-buffer "#chan@foonet/tester"
+ (funcall expect 5 "chester")
+ (funcall expect 5 "find the forester")
+ (erc-cmd-QUIT "")))
+
+ (ert-info ("Nick chester sees other nick tester in same channel")
+ (with-current-buffer "#chan@foonet/chester"
+ (funcall expect 5 "tester")
+ (funcall expect 5 "find the forester")))
+
+ (funcall after expect)))
+
+(ert-deftest erc-scenarios-base-association-samenet--reconnect-one ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-association-samenet
+ (lambda (expect)
+
+ (ert-info ("Connection tester reconnects")
+ (with-current-buffer "foonet/tester"
+ (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+ (funcall expect 10 "*** ERC finished")
+ (erc-cmd-RECONNECT)
+ (funcall expect 5 "debug mode")))
+
+ (ert-info ("Reassociated to same channel")
+ (with-current-buffer "#chan@foonet/tester"
+ (funcall expect 5 "chester")
+ (funcall expect 5 "welcome again")
+ (erc-cmd-QUIT "")))
+
+ (with-current-buffer "#chan@foonet/chester"
+ (funcall expect 5 "tester")
+ (funcall expect 5 "welcome again")
+ (funcall expect 5 "welcome again")
+ (erc-cmd-QUIT "")))))
+
+(ert-deftest erc-scenarios-base-association-samenet--new-buffer ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-association-samenet
+ (lambda (expect)
+
+ (ert-info ("Tester kills buffer and connects from scratch")
+
+ (let (port)
+ (with-current-buffer "foonet/tester"
+ (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+ (funcall expect 10 "*** ERC finished")
+ (setq port erc-session-port)
+ (kill-buffer))
+
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+
+ (erc-d-t-wait-for 5 (eq erc-network 'foonet)))))
+
+ (with-current-buffer "foonet/tester" (funcall expect 3 "debug mode"))
+
+ (ert-info ("Reassociated to same channel")
+ (with-current-buffer "#chan@foonet/tester"
+ (funcall expect 5 "chester")
+ (funcall expect 5 "welcome again")
+ (erc-cmd-QUIT "")))
+
+ (with-current-buffer "#chan@foonet/chester"
+ (funcall expect 5 "tester")
+ (funcall expect 5 "welcome again")
+ (funcall expect 5 "welcome again")
+ (erc-cmd-QUIT "")))))
+
+;;; erc-scenarios-base-association-samenet.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-association.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-association.el
new file mode 100644
index 0000000000..ed94dfab50
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-association.el
@@ -0,0 +1,196 @@
+;;; erc-scenarios-base-association.el --- base assoc scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(declare-function erc-network-name "erc-networks")
+(declare-function erc-network "erc-networks")
+(defvar erc-autojoin-channels-alist)
+(defvar erc-network)
+
+;; Two networks, same channel name, no confusion (no bouncer). Some
+;; of this draws from bug#47522 "foil-in-server-buf". It shows that
+;; disambiguation-related changes added for bug#48598 are not specific
+;; to bouncers.
+
+(defun erc-scenarios-common--base-association-multi-net (second-join)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/association/multi-net")
+ (erc-server-flood-penalty 0.1)
+ (erc-d-linger-secs 1)
+ (dumb-server-foonet-buffer (get-buffer-create "*server-foonet*"))
+ (dumb-server-barnet-buffer (get-buffer-create "*server-barnet*"))
+ (dumb-server-foonet (erc-d-run "localhost" t "server-foonet" 'foonet))
+ (dumb-server-barnet (erc-d-run "localhost" t "server-barnet" 'barnet))
+ (expect (erc-d-t-make-expecter)))
+
+ (ert-info ("Connect to foonet, join #chan")
+ (with-current-buffer
+ (erc :server "127.0.0.1"
+ :port (process-contact dumb-server-foonet :service)
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+ (funcall expect 3 "debug mode")
+ (erc-cmd-JOIN "#chan")))
+
+ (erc-d-t-wait-for 2 (get-buffer "#chan"))
+
+ (ert-info ("Connect to barnet, join #chan")
+ (with-current-buffer
+ (erc :server "127.0.0.1"
+ :port (process-contact dumb-server-barnet :service)
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+ (funcall expect 3 "debug mode")))
+
+ (funcall second-join)
+
+ (erc-d-t-wait-for 3 (get-buffer "#chan@barnet"))
+
+ (erc-d-t-wait-for 2 "Buf #chan now #chan@foonet"
+ (and (get-buffer "#chan@foonet") (not (get-buffer "#chan"))))
+
+ (ert-info ("All #chan@foonet output consumed")
+ (with-current-buffer "#chan@foonet"
+ (funcall expect 3 "bob")
+ (funcall expect 3 "was created on")
+ (funcall expect 3 "prosperous")))
+
+ (ert-info ("All #chan@barnet output consumed")
+ (with-current-buffer "#chan@barnet"
+ (funcall expect 3 "mike")
+ (funcall expect 3 "was created on")
+ (funcall expect 20 "ingenuous")))))
+
+(ert-deftest erc-scenarios-base-association-multi-net--baseline ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-association-multi-net
+ (lambda () (with-current-buffer "barnet" (erc-cmd-JOIN "#chan")))))
+
+;; The /join command only targets the current buffer's process. This
+;; recasts scenario bug#48598 "ambiguous-join" (which was based on
+;; bug#47522) to show that issuing superfluous /join commands
+;; (apparently fairly common) is benign.
+
+(ert-deftest erc-scenarios-base-association-multi-net--ambiguous-join ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-association-multi-net
+ (lambda ()
+ (ert-info ("Nonsensical JOIN attempts silently dropped.")
+ (with-current-buffer "foonet" (erc-cmd-JOIN "#chan"))
+ (sit-for 0.1)
+ (with-current-buffer "#chan" (erc-cmd-JOIN "#chan"))
+ (sit-for 0.1)
+ (erc-d-t-wait-for 2 (get-buffer "#chan"))
+ (erc-d-t-wait-for 1 "Only one #chan buffer exists"
+ (should (equal (erc-scenarios-common-buflist "#chan")
+ (list (get-buffer "#chan")))))
+ (with-current-buffer "*server-barnet*"
+ (erc-d-t-absent-for 0.1 "JOIN"))
+ (with-current-buffer "barnet" (erc-cmd-JOIN "#chan"))))))
+
+;; Playback for same channel on two networks routed correctly.
+;; Originally from Bug#48598: 28.0.50; buffer-naming collisions
+;; involving bouncers in ERC.
+
+(ert-deftest erc-scenarios-base-association-bouncer-history ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/association/bouncer-history")
+ (erc-d-t-cleanup-sleep-secs 1)
+ (erc-d-linger-secs 2)
+ (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+ (port (process-contact dumb-server :service))
+ (erc-server-flood-penalty 0.5)
+ (expect (erc-d-t-make-expecter))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo erc-server-process-foo
+ erc-server-buffer-bar erc-server-process-bar)
+
+ (ert-info ("Connect to foonet")
+ (with-current-buffer
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"))
+ (setq erc-server-process-foo erc-server-process)
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (funcall expect 5 "foonet")))
+
+ (erc-d-t-wait-for 5 (get-buffer "#chan"))
+
+ (ert-info ("Connect to barnet")
+ (with-current-buffer
+ (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester"))
+ (setq erc-server-process-bar erc-server-process)
+ (erc-d-t-wait-for 5 "Temporary name assigned"
+ (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (funcall expect 5 "barnet")))
+
+ (ert-info ("Server buffers are unique")
+ (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
+
+ (ert-info ("Networks correctly determined and adopted as buffer names")
+ (with-current-buffer erc-server-buffer-foo
+ (erc-d-t-wait-for 3 "network name foonet becomes buffer name"
+ (and (eq (erc-network) 'foonet) (string= (buffer-name) "foonet"))))
+ (with-current-buffer erc-server-buffer-bar
+ (erc-d-t-wait-for 3 "network name barnet becomes buffer name"
+ (and (eq (erc-network) 'barnet) (string= (buffer-name) "barnet")))))
+
+ (erc-d-t-wait-for 5 (get-buffer "#chan@barnet"))
+
+ (ert-info ("Two channel buffers created, original #chan renamed")
+ (should (= 4 (length (erc-buffer-list))))
+ (should (equal (list (get-buffer "#chan@barnet")
+ (get-buffer "#chan@foonet"))
+ (erc-scenarios-common-buflist "#chan"))))
+
+ (ert-info ("#chan@foonet is exclusive, no cross-contamination")
+ (with-current-buffer "#chan@foonet"
+ (erc-d-t-search-for 1 "<bob>")
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (should (eq erc-server-process erc-server-process-foo))))
+
+ (ert-info ("#chan@barnet is exclusive, no cross-contamination")
+ (with-current-buffer "#chan@barnet"
+ (erc-d-t-search-for 1 "<joe>")
+ (erc-d-t-absent-for 0.1 "<bob>")
+ (should (eq erc-server-process erc-server-process-bar))))
+
+ (ert-info ("All output sent")
+ (with-current-buffer "#chan@foonet"
+ (while (accept-process-output erc-server-process-foo))
+ (erc-d-t-search-for 3 "please your lordship"))
+ (with-current-buffer "#chan@barnet"
+ (while (accept-process-output erc-server-process-bar))
+ (erc-d-t-search-for 30 "I'll bid adieu")))))
+
+;;; erc-scenarios-base-association.el ends here
diff --git
a/test/lisp/erc/erc-scenarios/erc-scenarios-base-compat-rename-bouncer.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-compat-rename-bouncer.el
new file mode 100644
index 0000000000..a513c1c933
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-compat-rename-bouncer.el
@@ -0,0 +1,175 @@
+;;; erc-scenarios-compat-rename-bouncer.el --- compat-rename scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; Ensure deprecated option still respected when old default value
+;; explicitly set ("respected" in the sense of having names reflect
+;; dialed TCP endpoints with possible uniquifiers but without any of
+;; the old issues, pre-bug#48598).
+
+(defun erc-scenarios-common--base-compat-no-rename-bouncer (dialogs auto more)
+ (erc-scenarios-common-with-cleanup
+ ;; These actually *are* (assigned-)network-id related because
+ ;; our kludge assigns one after the fact.
+ ((erc-scenarios-common-dialog "base/network-id/bouncer")
+ (erc-d-t-cleanup-sleep-secs 1)
+ (erc-server-flood-penalty 0.1)
+ (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+ (port (process-contact dumb-server :service))
+ (chan-buf-foo (format "#chan@127.0.0.1:%d" port))
+ (chan-buf-bar (format "#chan@127.0.0.1:%d<2>" port))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-auto-reconnect auto)
+ erc-server-buffer-foo erc-server-process-foo
+ erc-server-buffer-bar erc-server-process-bar)
+
+ (ert-info ("Connect to foonet")
+ (with-current-buffer
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"
+ :id nil))
+ (setq erc-server-process-foo erc-server-process)
+ (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+ (erc-d-t-wait-for 3 "Final buffer name determined"
+ (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (funcall expect 5 "foonet")))
+
+ (ert-info ("Join #chan@foonet")
+ (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+ (funcall expect 5 "<alice>")))
+
+ (ert-info ("Connect to barnet")
+ (with-current-buffer
+ (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester"
+ :id nil))
+ (setq erc-server-process-bar erc-server-process)
+ (erc-d-t-wait-for 3 (eq (erc-network) 'barnet))
+ (erc-d-t-wait-for 3 "Final buffer name determined"
+ (string= (buffer-name) (format "127.0.0.1:%d<2>" port)))
+ (funcall expect 5 "barnet")))
+
+ (ert-info ("Server buffers are unique, no names based on IPs")
+ (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+ (should (equal (erc-scenarios-common-buflist "127.0.0.1")
+ (list (get-buffer (format "127.0.0.1:%d<2>" port))
+ (get-buffer (format "127.0.0.1:%d" port))))))
+
+ (ert-info ("Join #chan@barnet")
+ (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
+
+ (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
+ (equal (list (get-buffer chan-buf-bar)
+ (get-buffer chan-buf-foo))
+ (erc-scenarios-common-buflist "#chan")))
+
+ (ert-info ("#chan@127.0.0.1:$port is exclusive to foonet")
+ (with-current-buffer chan-buf-foo
+ (erc-d-t-search-for 1 "<bob>")
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (should (eq erc-server-process erc-server-process-foo))
+ (while (accept-process-output erc-server-process-foo))
+ (erc-d-t-search-for 1 "ape is dead")
+ (should-not (erc-server-process-alive))))
+
+ (ert-info ("#chan@127.0.0.1:$port<2> is exclusive to barnet")
+ (with-current-buffer chan-buf-bar
+ (erc-d-t-search-for 1 "<joe>")
+ (erc-d-t-absent-for 0.1 "<bob>")
+ (should (eq erc-server-process erc-server-process-bar))
+ (while (accept-process-output erc-server-process-bar))
+ (erc-d-t-search-for 1 "keeps you from dishonour")
+ (should-not (erc-server-process-alive))))
+
+ (when more (funcall more))))
+
+(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--basic ()
+ :tags '(:expensive-test)
+ (with-suppressed-warnings ((obsolete erc-rename-buffers))
+ (let (erc-rename-buffers)
+ (erc-scenarios-common--base-compat-no-rename-bouncer
+ '(foonet barnet) nil nil))))
+
+(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--reconnect ()
+ :tags '(:expensive-test)
+ (let ((erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+ (erc-d-match-handlers
+ (list :pass #'erc-scenarios-common--clash-rename-pass-handler))
+ (dialogs '(foonet-drop barnet-drop stub-again stub-again
+ foonet-again barnet-again))
+ (after
+ (lambda ()
+ (pcase-let* ((`(,barnet ,foonet)
+ (erc-scenarios-common-buflist "127.0.0.1"))
+ (port (process-contact (with-current-buffer foonet
+ erc-server-process)
+ :service)))
+
+ (ert-info ("Sanity check: barnet retains uniquifying suffix")
+ (should (string-suffix-p "<2>" (buffer-name barnet))))
+
+ ;; Simulate disconnection and `erc-server-auto-reconnect'
+ (ert-info ("Reconnect to foonet and barnet back-to-back")
+ (with-current-buffer foonet
+ (erc-d-t-wait-for 5 (erc-server-process-alive)))
+ (with-current-buffer barnet
+ (erc-d-t-wait-for 5 (erc-server-process-alive))))
+
+ (ert-info ("#chan@127.0.0.1:<port> is exclusive to foonet")
+ (with-current-buffer (format "#chan@127.0.0.1:%d" port)
+ (erc-d-t-search-for 1 "<alice>")
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (while (accept-process-output erc-server-process))
+ (erc-d-t-search-for 10 "please your lordship")))
+
+ (ert-info ("#chan@barnet is exclusive to barnet")
+ (with-current-buffer (format "#chan@127.0.0.1:%d<2>" port)
+ (erc-d-t-search-for 1 "<joe>")
+ (erc-d-t-absent-for 0.1 "<bob>")
+ (while (accept-process-output erc-server-process))
+ (erc-d-t-search-for 1 "much in private")))
+
+ ;; Ordering deterministic here even though not so for reconnect
+ (should (equal (list barnet foonet)
+ (erc-scenarios-common-buflist "127.0.0.1")))
+ (should (equal (list
+ (get-buffer (format "#chan@127.0.0.1:%d<2>" port))
+ (get-buffer (format "#chan@127.0.0.1:%d" port)))
+ (erc-scenarios-common-buflist "#chan")))))))
+
+ (with-suppressed-warnings ((obsolete erc-rename-buffers))
+ (let (erc-rename-buffers)
+ (erc-scenarios-common--base-compat-no-rename-bouncer dialogs
+ 'auto after)))))
+
+;;; erc-scenarios-compat-rename-bouncer.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-misc-regressions.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-misc-regressions.el
new file mode 100644
index 0000000000..1ec18259f0
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-misc-regressions.el
@@ -0,0 +1,135 @@
+;;; erc-scenarios-base-misc-regressions.el --- misc regressions scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; The added complexity of a request handler definitely stinks. But on
+;; some machines, the ordering from the selector is nondeterministic,
+;; whereas normally, the filter for the last process created (in the
+;; code) gets all the initial attention. FIXME delete obsolete comment
+
+(defun erc-scenarios--rebuffed-gapless-pass-handler (dialog exchange)
+ (when (eq (erc-d-dialog-name dialog) 'pass-stub)
+ (let* ((match (erc-d-exchange-match exchange 1))
+ (sym (if (string= match "foonet") 'foonet 'barnet)))
+ (should (member match (list "foonet" "barnet")))
+ (erc-d-load-replacement-dialog dialog sym 1))))
+
+(ert-deftest erc-scenarios-base-gapless-connect ()
+ :tags '(:expensive-test)
+ "Back-to-back entry-point invocations happen successfully.
+Originally from scenario rebuffed/gapless as explained in Bug#48598:
+28.0.50; buffer-naming collisions involving bouncers in ERC."
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/gapless-connect")
+ (erc-server-flood-penalty 0.1)
+ (erc-d-linger-secs 4)
+ (erc-server-flood-penalty erc-server-flood-penalty)
+ (erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+ (erc-d-match-handlers
+ (list :pass #'erc-scenarios--rebuffed-gapless-pass-handler))
+ (dumb-server (erc-d-run "localhost" t
+ 'pass-stub 'pass-stub 'barnet 'foonet))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo
+ erc-server-buffer-bar)
+
+ (ert-info ("Connect twice to same endpoint without pausing")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester")
+ erc-server-buffer-bar (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester")))
+
+ (ert-info ("Returned server buffers are unique")
+ (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
+
+ (ert-info ("Both connections still alive")
+ (should (get-process (format "erc-127.0.0.1-%d" port)))
+ (should (get-process (format "erc-127.0.0.1-%d<1>" port))))
+
+ (with-current-buffer erc-server-buffer-bar
+ (funcall expect 2 "marked as being away"))
+
+ (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#bar"))
+ (while (accept-process-output erc-server-process))
+ (funcall expect 2 "was created on")
+ (funcall expect 2 "his second fit"))
+
+ (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#foo"))
+ (while (accept-process-output erc-server-process))
+ (funcall expect 2 "was created on")
+ (funcall expect 2 "no use of him"))))
+
+;; This defends against a regression in `erc-server-PRIVMSG' caused by
+;; the removal of `erc-auto-query'. When an active channel buffer is
+;; killed off and PRIVMSGs arrive targeting it, the buffer should be
+;; recreated. See elsewhere for NOTICE logic, which is more complex.
+
+(ert-deftest erc-scenarios-base-channel-buffer-revival ()
+ :tags '(:expensive-test)
+
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/channel-buffer-revival")
+ (erc-d-linger-secs 0.5)
+ (dumb-server (erc-d-run "localhost" t 'foonet))
+ (port (process-contact dumb-server :service))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (ert-info ("Server buffer is unique and temp name is absent")
+ (erc-d-t-wait-for 1 (get-buffer "FooNet"))
+ (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+ (with-current-buffer erc-server-buffer-foo
+ (erc-cmd-JOIN "#chan")))
+
+ (ert-info ("Channel buffer #chan alive and well")
+ (with-current-buffer (erc-d-t-wait-for 8 (get-buffer "#chan"))
+ (erc-d-t-search-for 10 "Our queen and all her elves")
+ (kill-buffer)))
+
+ (should-not (get-buffer "#chan"))
+
+ (ert-info ("Channel buffer #chan revived")
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+ (erc-d-t-search-for 10 "and be prosperous")))))
+
+;;; erc-scenarios-base-misc-regressions.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-id.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-id.el
new file mode 100644
index 0000000000..e4db3fc054
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-id.el
@@ -0,0 +1,34 @@
+;;; erc-scenarios-base-netid-bouncer-id.el --- net-id bouncer ID scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--id-foo ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer '(:foo-id t) 'foonet 'barnet))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--id-bar ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer '(:bar-id t) 'foonet 'barnet))
+
+;;; erc-scenarios-base-netid-bouncer-id.el ends here
diff --git
a/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-base.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-base.el
new file mode 100644
index 0000000000..681e6cd469
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-base.el
@@ -0,0 +1,30 @@
+;;; erc-scenarios-base-netid-bouncer-recon-base.el --- net-id base scenarios
-*- lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--recon-base ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer--reconnect nil nil))
+
+;;; erc-scenarios-base-netid-bouncer-recon-base.el ends here
diff --git
a/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-both.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-both.el
new file mode 100644
index 0000000000..73f9efdc8c
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-both.el
@@ -0,0 +1,32 @@
+;;; erc-scenarios-base-netid-bouncer-recon-both.el --- net-id both scenarios
-*- lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(require 'erc-scenarios-common)
+
+(ert-deftest erc-scenarios-base-netid-bouncer--recon-both ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id 'bar-id))
+
+;;; erc-scenarios-base-netid-bouncer-recon-both.el ends here
diff --git
a/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-id.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-id.el
new file mode 100644
index 0000000000..132d7eeb03
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer-recon-id.el
@@ -0,0 +1,35 @@
+;;; erc-scenarios-base-netid-bouncer-recon-id.el --- recon ID scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--reconnect-id-foo ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id nil))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--reconnect-id-bar ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer--reconnect nil 'bar-id))
+
+
+;;; erc-scenarios-base-netid-bouncer-recon-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer.el
new file mode 100644
index 0000000000..bd71e81bb5
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-bouncer.el
@@ -0,0 +1,35 @@
+;;; erc-scenarios-base-netid-bouncer.el --- net-id bouncer scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--base ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer () 'foonet 'barnet))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--both ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-bouncer '(:foo-id t :bar-id t)
+ 'foonet 'barnet))
+
+;;; erc-scenarios-base-netid-bouncer.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-samenet.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-samenet.el
new file mode 100644
index 0000000000..86b0388eec
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-netid-samenet.el
@@ -0,0 +1,147 @@
+;;; erc-scenarios-base-network-id-samenet.el --- netid-id samenet scenarios
-*- lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+(cl-defun erc-scenarios-common--base-network-id-same-network
+ ((&key nick id server chan
+ &aux (nick-a nick) (id-a id) (serv-buf-a server) (chan-buf-a chan))
+ (&key nick id server chan
+ &aux (nick-b nick) (id-b id) (serv-buf-b server) (chan-buf-b chan)))
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/network-id/same-network")
+ (dumb-server (erc-d-run "localhost" t 'tester 'chester))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-flood-penalty 0.1)
+ (erc-server-flood-margin 30)
+ erc-serv-buf-a erc-serv-buf-b)
+
+ (ert-info ("Connect to foonet with nick tester")
+ (with-current-buffer
+ (setq erc-serv-buf-a (erc :server "127.0.0.1"
+ :port port
+ :nick nick-a
+ :password "changeme"
+ :full-name nick-a
+ :id id-a))
+ (erc-scenarios-common-assert-initial-buf-name id-a port)
+ (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+ (ert-info ("Connect to foonet with nick chester")
+ (with-current-buffer
+ (setq erc-serv-buf-b (erc :server "127.0.0.1"
+ :port port
+ :nick nick-b
+ :password "changeme"
+ :full-name nick-b
+ :id id-b))
+ (erc-scenarios-common-assert-initial-buf-name id-b port)))
+
+ (erc-d-t-wait-for 3 (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+ (with-current-buffer erc-serv-buf-a
+ (should (string= (buffer-name) serv-buf-a))
+ (funcall expect 8 "debug mode")
+ (erc-cmd-JOIN "#chan"))
+
+ (with-current-buffer erc-serv-buf-b
+ (should (string= (buffer-name) serv-buf-b))
+ (funcall expect 8 "debug mode")
+ (erc-cmd-JOIN "#chan"))
+
+ (erc-d-t-wait-for 10 (get-buffer chan-buf-a))
+ (erc-d-t-wait-for 10 (get-buffer chan-buf-b))
+
+ (ert-info ("Greets other nick in same channel")
+ (with-current-buffer chan-buf-a
+ (funcall expect 5 "chester")
+ (funcall expect 5 "find the forester")
+ (erc-cmd-MSG "#chan chester: hi")))
+
+ (ert-info ("Sees other nick in same channel")
+ (with-current-buffer chan-buf-b
+ (funcall expect 5 "tester")
+ (funcall expect 10 "<tester> chester: hi")
+ (funcall expect 5 "This was lofty")
+ (erc-cmd-MSG "#chan hi tester")))
+
+ (with-current-buffer chan-buf-a
+ (funcall expect 5 "To employ you towards")
+ (erc-cmd-QUIT ""))
+
+ (with-current-buffer chan-buf-b
+ (funcall expect 5 "To employ you towards")
+ (erc-cmd-QUIT ""))))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--two-ids ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-same-network
+ (list :nick "tester"
+ :id 'tester/foonet
+ :server "tester/foonet"
+ :chan "#chan@tester/foonet")
+ (list :nick "chester"
+ :id 'chester/foonet
+ :server "chester/foonet"
+ :chan "#chan@chester/foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--one-id-tester ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-same-network
+ (list :nick "tester"
+ :id 'tester/foonet
+ :server "tester/foonet"
+ :chan "#chan@tester/foonet")
+ (list :nick "chester"
+ :id nil
+ :server "foonet"
+ :chan "#chan@foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--one-id-chester ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-same-network
+ (list :nick "tester"
+ :id nil
+ :server "foonet"
+ :chan "#chan@foonet")
+ (list :nick "chester"
+ :id 'chester/foonet
+ :server "chester/foonet"
+ :chan "#chan@chester/foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--no-ids ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common--base-network-id-same-network
+ (list :nick "tester"
+ :id nil
+ :server "foonet/tester"
+ :chan "#chan@foonet/tester") ; <- note net before nick
+ (list :nick "chester"
+ :id nil
+ :server "foonet/chester"
+ :chan "#chan@foonet/chester")))
+
+;;; erc-scenarios-base-network-id-samenet.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-reconnect.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-reconnect.el
new file mode 100644
index 0000000000..56b7570c29
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-reconnect.el
@@ -0,0 +1,227 @@
+;;; erc-scenarios-base-reconnect.el --- Base-reconnect scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; This ensures we only reconnect `erc-server-reconnect-attempts'
+;; (rather than infinitely many) times, which can easily happen when
+;; tweaking code related to process sentinels in erc-backend.el.
+
+(ert-deftest erc-scenarios-base-reconnect-timer ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/reconnect")
+ (dumb-server (erc-d-run "localhost" t 'timer 'timer 'timer-last))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-auto-reconnect t)
+ erc-autojoin-channels-alist
+ erc-server-buffer)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (ert-info ("Server tries to connect thrice (including initial attempt)")
+ (with-current-buffer erc-server-buffer
+ (dotimes (n 3)
+ (ert-info ((format "Attempt %d" n))
+ (funcall expect 3 "Opening connection")
+ (funcall expect 2 "Password incorrect")
+ (funcall expect 2 "Connection failed!")
+ (funcall expect 2 "Re-establishing connection")))
+ (ert-info ("Prev attempt was final")
+ (erc-d-t-absent-for 1 "Opening connection" (point)))))
+
+ (ert-info ("Server buffer is unique and temp name is absent")
+ (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
+ (erc-scenarios-common-buflist "127.0.0.1"))))))
+
+(defun erc-scenarios-common--base-reconnect-options (test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/reconnect")
+ (dumb-server (erc-d-run "localhost" t 'options 'options-again))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-flood-penalty 0.1)
+ (erc-server-auto-reconnect t)
+ erc-autojoin-channels-alist
+ erc-server-buffer)
+
+ (should (memq 'autojoin erc-modules))
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (funcall expect 10 "debug mode")))
+
+ (ert-info ("Wait for some output in channels")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+ (funcall expect 10 "welcome")))
+
+ (ert-info ("Server buffer shows connection failed")
+ (with-current-buffer erc-server-buffer
+ (funcall expect 10 "Connection failed! Re-establishing")))
+
+ (should (equal erc-autojoin-channels-alist '((FooNet "#chan"))))
+
+ (funcall test)
+
+ (with-current-buffer "FooNet" (erc-cmd-JOIN "#spam"))
+
+ (erc-d-t-wait-for 5 "Channel #spam shown when autojoined"
+ (eq (window-buffer) (get-buffer "#spam")))
+
+ (ert-info ("Wait for auto reconnect")
+ (with-current-buffer erc-server-buffer
+ (funcall expect 10 "still in debug mode")))
+
+ (ert-info ("Wait for activity to recommence in channels")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+ (funcall expect 10 "forest of Arden"))
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
+ (funcall expect 10 "her elves come here anon")))))
+
+(ert-deftest erc-scenarios-base-reconnect-options--default ()
+ :tags '(:expensive-test)
+ (should (eq erc-join-buffer 'buffer))
+ (should-not erc-reconnect-display)
+
+ ;; FooNet (the server buffer) is not switched to because it's
+ ;; already current (but not shown) when `erc-open' is called. See
+ ;; related conditional guard towards the end of that function.
+
+ (erc-scenarios-common--base-reconnect-options
+ (lambda ()
+ (pop-to-buffer-same-window "*Messages*")
+
+ (erc-d-t-ensure-for 1 "Server buffer not shown"
+ (not (eq (window-buffer) (get-buffer "FooNet"))))
+
+ (erc-d-t-wait-for 5 "Channel #chan shown when autojoined"
+ (eq (window-buffer) (get-buffer "#chan"))))))
+
+(ert-deftest erc-scenarios-base-reconnect-options--bury ()
+ :tags '(:expensive-test)
+ (should (eq erc-join-buffer 'buffer))
+ (should-not erc-reconnect-display)
+
+ (let ((erc-reconnect-display 'bury))
+ (erc-scenarios-common--base-reconnect-options
+
+ (lambda ()
+ (pop-to-buffer-same-window "*Messages*")
+
+ (erc-d-t-ensure-for 1 "Server buffer not shown"
+ (not (eq (window-buffer) (get-buffer "FooNet"))))
+
+ (erc-d-t-ensure-for 3 "Channel #chan not shown"
+ (not (eq (window-buffer) (get-buffer "#chan"))))
+
+ (eq (window-buffer) (messages-buffer))))))
+
+;; Upon reconnecting, playback for channel and target buffers is
+;; routed correctly. Autojoin is irrelevant here, but for the
+;; skeptical, see `erc-scenarios-common--join-network-id', which
+;; overlaps with this and includes spurious JOINs ignored by the
+;; server.
+
+(ert-deftest erc-scenarios-base-association-reconnect-playback ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/association/reconnect-playback")
+ (erc-d-linger-secs 0.5)
+ (erc-server-flood-penalty 0.1)
+ (erc-server-flood-margin 30)
+ (dumb-server (erc-d-run "localhost" t 'foonet 'foonet-again))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (ert-info ("Setup")
+
+ (ert-info ("Server buffer is unique and temp name is absent")
+ (erc-d-t-wait-for 3 (get-buffer "foonet"))
+ (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+ (ert-info ("Channel buffer #chan playback received")
+ (with-current-buffer (erc-d-t-wait-for 8 (get-buffer "#chan"))
+ (funcall expect 10 "But purgatory")))
+
+ (ert-info ("Ask for help from services or bouncer bot")
+ (with-current-buffer erc-server-buffer-foo
+ (erc-cmd-MSG "*status help")))
+
+ (ert-info ("Help received")
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "*status"))
+ (funcall expect 10 "Rehash")))
+
+ (ert-info ("#chan convo done")
+ (with-current-buffer "#chan"
+ (funcall expect 10 "most egregious indignity"))))
+
+ ;; KLUDGE (see note above test)
+ (should erc-autojoin-channels-alist)
+ (setq erc-autojoin-channels-alist nil)
+
+ (with-current-buffer erc-server-buffer-foo
+ (erc-cmd-QUIT "")
+ (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+ (erc-cmd-RECONNECT))
+
+ (ert-info ("Channel buffer found and associated")
+ (with-current-buffer "#chan"
+ (funcall expect 10 "Wilt thou rest damned")))
+
+ (ert-info ("Help buffer found and associated")
+ (with-current-buffer "*status"
+ (erc-scenarios-common-say "help")
+ (funcall expect 10 "Restart ZNC")))
+
+ (ert-info ("#chan convo done")
+ (with-current-buffer "#chan"
+ (funcall expect 10 "here comes the lady")))))
+
+;;; erc-scenarios-base-reconnect.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-renick.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-renick.el
new file mode 100644
index 0000000000..e10aa5cc17
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-renick.el
@@ -0,0 +1,310 @@
+;;; erc-scenarios-base-renick.el --- Re-nicking scenarios -*- lexical-binding:
t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; The server changes your nick just after registration.
+
+(ert-deftest erc-scenarios-base-renick-self-auto ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/renick/self")
+ (erc-d-linger-secs 0.1)
+ (erc-server-flood-penalty 0.1)
+ (dumb-server (erc-d-run "localhost" t 'auto))
+ (port (process-contact dumb-server :service))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
+ (erc-d-t-search-for 10 "Your new nickname is dummy"))
+
+ (ert-info ("Joined by bouncer to #foo, own nick present")
+ (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+ (erc-d-t-search-for 10 "dummy")
+ (erc-d-t-search-for 10 "On Thursday")))))
+
+;; You change your nickname manually in a server buffer; a message is
+;; printed in channel buffers.
+
+(ert-deftest erc-scenarios-base-renick-self-manual ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/renick/self")
+ (erc-d-linger-secs 0.1)
+ (erc-server-flood-penalty 0.1)
+ (dumb-server (erc-d-run "localhost" t 'manual))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (erc-d-t-wait-for 3 (get-buffer "foonet"))
+
+ (ert-info ("Joined by bouncer to #foo, own nick present")
+ (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+ (funcall expect 5 "tester")
+ (funcall expect 5 "On Thursday")
+ (erc-with-server-buffer (erc-cmd-NICK "dummy"))
+ (funcall expect 5 "Your new nickname is dummy")
+ (funcall expect 5 "<bob> dummy: Hi")
+ ;; Regression in which changing a nick would trigger #foo@foonet
+ (erc-d-t-ensure-for 0.4 (equal (buffer-name) "#foo"))))))
+
+;; You connect to the same network with two different nicks. You
+;; manually change the first nick at some point, and buffer names are
+;; updated correctly.
+
+(ert-deftest erc-scenarios-base-renick-self-qualified ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/renick/self")
+ (dumb-server (erc-d-run "localhost" t 'qual-tester 'qual-chester))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-flood-penalty 0.1)
+ (erc-server-flood-margin 30)
+ erc-serv-buf-a erc-serv-buf-b)
+
+ (ert-info ("Connect to foonet with nick tester")
+ (with-current-buffer
+ (setq erc-serv-buf-a (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester"))
+ (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+ (ert-info ("Connect to foonet with nick chester")
+ (with-current-buffer
+ (setq erc-serv-buf-b (erc :server "127.0.0.1"
+ :port port
+ :nick "chester"
+ :password "changeme"
+ :full-name "chester"))))
+
+ (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
+ (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+ (with-current-buffer "foonet/tester"
+ (funcall expect 3 "debug mode")
+ (erc-cmd-JOIN "#chan"))
+
+ (with-current-buffer "foonet/chester"
+ (funcall expect 3 "debug mode")
+ (erc-cmd-JOIN "#chan"))
+
+ (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
+ (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
+
+ (ert-info ("Greets other nick in same channel")
+ (with-current-buffer "#chan@foonet/tester"
+ (funcall expect 5 "<bob> chester, welcome!")
+ (erc-cmd-NICK "dummy")
+ (funcall expect 5 "Your new nickname is dummy")
+ (funcall expect 5 "find the forester")
+ (erc-d-t-wait-for 5 (string= (buffer-name) "#chan@foonet/dummy"))))
+
+ (ert-info ("Renick propagated throughout all buffers of process")
+ (should-not (get-buffer "#chan@foonet/tester"))
+ (should-not (get-buffer "foonet/tester"))
+ (should (get-buffer "foonet/dummy")))))
+
+;; When a channel user changes their nick, any query buffers for them
+;; are updated.
+
+(ert-deftest erc-scenarios-base-renick-queries-solo ()
+ :tags '(:expensive-test)
+
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/renick/queries")
+ (erc-d-linger-secs 0.1)
+ (erc-server-flood-penalty 0.1)
+ (erc-server-flood-margin 20)
+ (dumb-server (erc-d-run "localhost" t 'solo))
+ (port (process-contact dumb-server :service))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (erc-d-t-wait-for 1 (get-buffer "foonet"))
+
+ (ert-info ("Joined by bouncer to #foo, pal persent")
+ (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+ (erc-d-t-search-for 1 "On Thursday")
+ (erc-scenarios-common-say "hi")))
+
+ (erc-d-t-wait-for 10 "Query buffer appears with message from pal"
+ (get-buffer "Lal"))
+
+ (ert-info ("Chat with pal, who changes name")
+ (with-current-buffer "Lal"
+ (erc-d-t-search-for 3 "hello")
+ (erc-scenarios-common-say "hi")
+ (erc-d-t-search-for 10 "is now known as Linguo")
+ (should-not (search-forward "is now known as Linguo" nil t))))
+
+ (erc-d-t-wait-for 1 (get-buffer "Linguo"))
+ (should-not (get-buffer "Lal"))
+
+ (with-current-buffer "Linguo" (erc-scenarios-common-say "howdy Linguo"))
+
+ (with-current-buffer "#foo"
+ (erc-d-t-search-for 10 "is now known as Linguo")
+ (should-not (search-forward "is now known as Linguo" nil t))
+ (erc-cmd-PART ""))
+
+ (with-current-buffer "Linguo"
+ (erc-d-t-search-for 10 "get along"))))
+
+;; You share a channel and a query buffer with a user on two different
+;; networks (through a proxy). The user changes their nick on both
+;; networks at the same time. Query buffers are updated accordingly.
+
+(ert-deftest erc-scenarios-base-renick-queries-bouncer ()
+ :tags '(:expensive-test)
+
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/renick/queries")
+ (erc-d-linger-secs 1.5)
+ (erc-server-flood-penalty 0.1)
+ (erc-server-flood-margin 30)
+ (dumb-server (erc-d-run "localhost" t 'bouncer-foonet 'bouncer-barnet))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ erc-accidental-paste-threshold-seconds
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo
+ erc-server-buffer-bar)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (erc-d-t-wait-for 5 (get-buffer "foonet"))
+
+ (ert-info ("Connect to barnet")
+ (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-bar
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (erc-d-t-wait-for 5 (get-buffer "barnet"))
+ (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+
+ (ert-info ("Joined by bouncer to #chan@foonet, pal persent")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@foonet"))
+ (funcall expect 1 "rando")
+ (funcall expect 1 "simply misused")))
+
+ (ert-info ("Joined by bouncer to #chan@barnet, pal persent")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@barnet"))
+ (funcall expect 1 "rando")
+ (funcall expect 1 "come, sir, I am")))
+
+ (ert-info ("Query buffer exists for rando@foonet")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@foonet"))
+ (funcall expect 1 "guess not")
+ (erc-scenarios-common-say "I here")))
+
+ (ert-info ("Query buffer exists for rando@barnet")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@barnet"))
+ (funcall expect 2 "rentacop")
+ (erc-scenarios-common-say "Linda said you were gonna kill me.")))
+
+ (ert-info ("Sync convo for rando@foonet")
+ (with-current-buffer "rando@foonet"
+ (funcall expect 1 "u are dumb")
+ (erc-scenarios-common-say "not so")))
+
+ (ert-info ("Sync convo for rando@barnet")
+ (with-current-buffer "rando@barnet"
+ (funcall expect 3 "I never saw her before")
+ (erc-scenarios-common-say "You aren't with Wage?")))
+
+ (erc-d-t-wait-for 3 (get-buffer "frenemy@foonet"))
+ (erc-d-t-wait-for 3 (get-buffer "frenemy@barnet"))
+ (should-not (get-buffer "rando@foonet"))
+ (should-not (get-buffer "rando@barnet"))
+
+ (with-current-buffer "frenemy@foonet"
+ (funcall expect 1 "now known as")
+ (funcall expect 1 "doubly so"))
+
+ (with-current-buffer "frenemy@barnet"
+ (funcall expect 1 "now known as")
+ (funcall expect 1 "reality picture"))
+
+ (when noninteractive
+ (with-current-buffer "frenemy@barnet" (kill-buffer))
+ (erc-d-t-wait-for 2 (get-buffer "frenemy"))
+ (should-not (get-buffer "frenemy@foonet")))
+
+ (with-current-buffer "#chan@foonet"
+ (funcall expect 10 "is now known as frenemy")
+ (should-not (search-forward "now known as frenemy" nil t)) ; regression
+ (funcall expect 10 "words are razors"))
+
+ (with-current-buffer "#chan@barnet"
+ (funcall expect 10 "is now known as frenemy")
+ (should-not (search-forward "now known as frenemy" nil t))
+ (while (accept-process-output erc-server-process))
+ (erc-d-t-search-for 25 "I have lost"))))
+
+;;; erc-scenarios-base-renick.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-reuse-buffers.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-reuse-buffers.el
new file mode 100644
index 0000000000..fa10e592ec
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-reuse-buffers.el
@@ -0,0 +1,189 @@
+;;; erc-scenarios-base-reuse-buffers.el --- base-reuse-buffers scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+(defun erc-scenarios-common--base-reuse-buffers-server-buffers (&optional more)
+ "Show that `erc-reuse-buffers' doesn't affect server buffers.
+Overlaps some with `clash-of-chans/uniquify'. Adapted from
+rebuffed/reuseless, described in Bug#48598: 28.0.50; buffer-naming
+collisions involving bouncers in ERC. Run EXTRA."
+ (erc-scenarios-common-with-cleanup
+ ((erc-d-linger-secs 1)
+ (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+ (port (process-contact dumb-server :service))
+ erc-autojoin-channels-alist)
+
+ (ert-info ("Connect to foonet")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (erc-d-t-search-for 12 "marked as being away")))
+
+ (ert-info ("Connect to barnet")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (erc-d-t-search-for 45 "marked as being away")))
+
+ (erc-d-t-wait-for 2 (get-buffer "foonet"))
+ (erc-d-t-wait-for 2 (get-buffer "barnet"))
+
+ (ert-info ("Server buffers are unique, no IP-based names")
+ (should-not (eq (get-buffer "foonet") (get-buffer "barnet")))
+ (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+ (when more (funcall more))))
+
+(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--enabled ()
+ :tags '(:expensive-test)
+ (should erc-reuse-buffers)
+ (let ((erc-scenarios-common-dialog "base/reuse-buffers/server-buffers"))
+ (erc-scenarios-common--base-reuse-buffers-server-buffers)))
+
+(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--disabled ()
+ :tags '(:expensive-test)
+ (should erc-reuse-buffers)
+ (let ((erc-scenarios-common-dialog "base/reuse-buffers/server-buffers")
+ erc-reuse-buffers)
+ (erc-scenarios-common--base-reuse-buffers-server-buffers)))
+
+;; This also asserts that `erc-cmd-JOIN' is no longer susceptible to a
+;; regression introduced in 28.1 (ERC 5.4) that caused phantom target
+;; buffers of the form target/server to be created via
+;; `switch-to-buffer' ("phantom" because they would go unused"). This
+;; would happen (in place of a JOIN being sent out) when a previously
+;; used (parted) target buffer existed and `erc-reuse-buffers' was
+;; nil.
+;;
+;; Note: All the `erc-get-channel-user' calls have to do with the fact
+;; that `erc-default-target' relies on the less-than-well-defined
+;; `erc-default-recipients' and is thus overloaded in the sense of
+;; being used both for retrieving a target name and checking if
+;; channel has been PARTed. While not ideal, `erc-get-channel-user'
+;; can (also) be used to detect the latter.
+
+(defun erc-scenarios-common--base-reuse-buffers-channel-buffers ()
+ "The option `erc-reuse-buffers' is still respected when nil.
+Adapted from scenario clash-of-chans/uniquify described in Bug#48598:
+28.0.50; buffer-naming collisions involving bouncers in ERC."
+ (let ((expect (erc-d-t-make-expecter))
+ (server-process-bar (with-current-buffer "barnet" erc-server-process))
+ (server-process-foo (with-current-buffer "foonet" erc-server-process)))
+
+ (ert-info ("Unique #chan buffers exist")
+ (let ((chan-bufs (erc-scenarios-common-buflist "#chan"))
+ (names '("#chan@barnet" "#chan@foonet")))
+ (should (member (buffer-name (pop chan-bufs)) names))
+ (should (member (buffer-name (pop chan-bufs)) names))
+ (should-not chan-bufs)))
+
+ (ert-info ("#chan@foonet is exclusive and not contaminated")
+ (with-current-buffer "#chan@foonet"
+ (funcall expect 1 "<bob>")
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (funcall expect 1 "strength to climb")
+ (should (eq erc-server-process server-process-foo))))
+
+ (ert-info ("#chan@barnet is exclusive and not contaminated")
+ (with-current-buffer "#chan@barnet"
+ (funcall expect 1 "<joe>")
+ (erc-d-t-absent-for 0.1 "<bob>")
+ (funcall expect 1 "the loudest noise")
+ (should (eq erc-server-process server-process-bar))))
+
+ (ert-info ("Part #chan@foonet")
+ (with-current-buffer "#chan@foonet"
+ (erc-d-t-search-for 1 "shake my sword")
+ (erc-cmd-PART "#chan")
+ (funcall expect 3 "You have left channel #chan")
+ (erc-cmd-JOIN "#chan")))
+
+ (ert-info ("Part #chan@barnet")
+ (with-current-buffer "#chan@barnet"
+ (funcall expect 3 "Arm it in rags")
+ (should (erc-get-channel-user (erc-current-nick)))
+ (erc-cmd-PART "#chan")
+ (funcall expect 3 "You have left channel #chan")
+ (should-not (erc-get-channel-user (erc-current-nick)))
+ (erc-cmd-JOIN "#chan")))
+
+ (erc-d-t-wait-for 3 "New unique target buffer for #chan@foonet created"
+ (get-buffer "#chan@foonet<2>"))
+
+ (ert-info ("Activity continues in new, <n>-suffixed #chan@foonet buffer")
+ (with-current-buffer "#chan@foonet"
+ (should-not (erc-get-channel-user (erc-current-nick))))
+ (with-current-buffer "#chan@foonet<2>"
+ (should (erc-get-channel-user (erc-current-nick)))
+ (funcall expect 2 "You have joined channel #chan")
+ (funcall expect 2 "#chan was created on")
+ (funcall expect 2 "<alice>")
+ (should (eq erc-server-process server-process-foo))
+ (erc-d-t-absent-for 0.2 "<joe>")))
+
+ (erc-d-t-wait-for 3 "New unique target buffer for #chan@barnet created"
+ (get-buffer "#chan@barnet<2>"))
+
+ (ert-info ("Activity continues in new, <n>-suffixed #chan@barnet buffer")
+ (with-current-buffer "#chan@barnet"
+ (should-not (erc-get-channel-user (erc-current-nick))))
+ (with-current-buffer "#chan@barnet<2>"
+ (funcall expect 2 "You have joined channel #chan")
+ (funcall expect 1 "Users on #chan: @mike joe tester")
+ (funcall expect 2 "<mike>")
+ (should (eq erc-server-process server-process-bar))
+ (erc-d-t-absent-for 0.2 "<bob>")))
+
+ (ert-info ("Two new chans created for a total of four")
+ (let* ((bufs (erc-scenarios-common-buflist "#chan"))
+ (names (sort (mapcar #'buffer-name bufs) #'string<)))
+ (should (equal names '("#chan@barnet" "#chan@barnet<2>"
+ "#chan@foonet" "#chan@foonet<2>")))))
+
+ (ert-info ("All output sent")
+ (with-current-buffer "#chan@foonet<2>"
+ (while (accept-process-output server-process-foo))
+ (funcall expect 3 "most lively"))
+ (with-current-buffer "#chan@barnet<2>"
+ (while (accept-process-output server-process-bar))
+ (funcall expect 3 "soul black")))))
+
+(ert-deftest erc-scenarios-base-reuse-buffers-channel-buffers--disabled ()
+ :tags '(:expensive-test)
+ (should erc-reuse-buffers)
+ (let ((erc-scenarios-common-dialog "base/reuse-buffers/channel-buffers")
+ (erc-server-flood-penalty 0.1)
+ erc-reuse-buffers)
+ (erc-scenarios-common--base-reuse-buffers-server-buffers
+ #'erc-scenarios-common--base-reuse-buffers-channel-buffers)))
+
+;;; erc-scenarios-base-reuse-buffers.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-base-unstable.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-base-unstable.el
new file mode 100644
index 0000000000..4739ce9eba
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-base-unstable.el
@@ -0,0 +1,137 @@
+;;; erc-scenarios-base-unstable.el --- base unstable scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; Not unstable, but stashed here for now
+
+(ert-deftest erc-scenarios-aux-unix-socket ()
+ :tags '(:expensive-test)
+ (skip-unless (featurep 'make-network-process '(:family local)))
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/renick/self")
+ (erc-d-linger-secs 0.1)
+ (erc-server-flood-penalty 0.1)
+ (sock (expand-file-name "erc-d.sock" temporary-file-directory))
+ (erc-scenarios-common-extra-teardown (lambda ()
+ (delete-file sock)))
+ (erc-server-connect-function
+ (lambda (n b _ p &rest r)
+ (apply #'make-network-process
+ `(:name ,n :buffer ,b :service ,p :family local ,@r))))
+ (dumb-server (erc-d-run nil sock 'auto))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "fake"
+ :port sock
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "fake:%s" sock)))))
+
+ (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
+ (erc-d-t-search-for 10 "Your new nickname is dummy"))
+
+ (ert-info ("Joined by bouncer to #foo, own nick present")
+ (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#foo"))
+ (erc-d-t-search-for 10 "dummy")
+ (erc-d-t-search-for 10 "On Thursday")))))
+
+;; See `erc-networks--rename-server-buffer'. A perceived loss in
+;; network connectivity turns out to be a false alarm, but the bouncer
+;; has already accepted the second connection
+
+(defun erc-scenarios--base-aborted-reconnect ()
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/reconnect")
+ (erc-d-t-cleanup-sleep-secs 1)
+ (erc-d-linger-secs 0.5)
+ (dumb-server (erc-d-run "localhost" t 'aborted 'aborted-dupe))
+ (port (process-contact dumb-server :service))
+ erc-autojoin-channels-alist
+ erc-server-buffer-foo)
+
+ (ert-info ("Connect to foonet")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester"))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (ert-info ("Server buffer is unique and temp name is absent")
+ (erc-d-t-wait-for 1 (get-buffer "FooNet"))
+ (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+ (with-current-buffer erc-server-buffer-foo
+ (erc-cmd-JOIN "#chan")))
+
+ (ert-info ("Channel buffer #chan alive and well")
+ (with-current-buffer (erc-d-t-wait-for 4 (get-buffer "#chan"))
+ (erc-d-t-search-for 10 "welcome")))
+
+ (ert-info ("Connect to foonet again")
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester"))
+ (let ((inhibit-message noninteractive))
+ (with-current-buffer erc-server-buffer-foo
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (erc-d-t-wait-for 5 (not (erc-server-process-alive)))
+ (erc-d-t-search-for 10 "FooNet still connected"))))
+
+ (ert-info ("Server buffer is unique and temp name is absent")
+ (should (equal (list (get-buffer "FooNet"))
+ (erc-scenarios-common-buflist "FooNet")))
+ (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
+ (erc-scenarios-common-buflist "127.0.0.1"))))
+
+ (ert-info ("Channel buffer #chan still going")
+ (with-current-buffer "#chan"
+ (erc-d-t-search-for 10 "and be prosperous")))))
+
+(ert-deftest erc-scenarios-base-aborted-reconnect ()
+ :tags '(:unstable)
+ (let ((tries 3)
+ (timeout 1)
+ failed)
+ (while (condition-case _err
+ (progn
+ (erc-scenarios--base-aborted-reconnect)
+ nil)
+ (ert-test-failed
+ (message "Test %S failed; %s attempt(s) remaining."
+ (ert-test-name (ert-running-test))
+ tries)
+ (sleep-for (cl-incf timeout))
+ (not (setq failed (zerop (cl-decf tries)))))))
+ (should-not failed)))
+
+;;; erc-scenarios-base-unstable.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-newcmd-id.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-newcmd-id.el
new file mode 100644
index 0000000000..8b8166f8b1
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-newcmd-id.el
@@ -0,0 +1,50 @@
+;;; erc-scenarios-join-netid-newcmd-id.el --- join netid newcmd scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd-id ()
+ :tags '(:expensive-test)
+ (let ((connect (lambda ()
+ (erc :server "127.0.0.1"
+ :port (with-current-buffer "oofnet"
+ (process-contact erc-server-process :service))
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"
+ :id 'oofnet))))
+ (erc-scenarios-common--join-network-id connect 'oofnet nil)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd-ids ()
+ :tags '(:expensive-test)
+ (let ((connect (lambda ()
+ (erc :server "127.0.0.1"
+ :port (with-current-buffer "oofnet"
+ (process-contact erc-server-process :service))
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"
+ :id 'oofnet))))
+ (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
+
+;;; erc-scenarios-join-netid-newcmd-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-newcmd.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-newcmd.el
new file mode 100644
index 0000000000..2eac8cd523
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-newcmd.el
@@ -0,0 +1,37 @@
+;;; erc-scenarios-join-netid-newcmd.el --- join netid newcmd scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd ()
+ :tags '(:expensive-test)
+ (let ((connect (lambda ()
+ (erc :server "127.0.0.1"
+ :port (with-current-buffer "foonet"
+ (process-contact erc-server-process :service))
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"))))
+ (erc-scenarios-common--join-network-id connect nil nil)))
+
+;;; erc-scenarios-join-netid-newcmd.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-recon-id.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-recon-id.el
new file mode 100644
index 0000000000..14ca1054b3
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-recon-id.el
@@ -0,0 +1,46 @@
+;;; erc-scenarios-join-netid-recon-id.el --- join-netid-recon scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--recon-id ()
+ :tags '(:expensive-test)
+ (let ((connect (lambda ()
+ (with-current-buffer "oofnet"
+ (erc-cmd-RECONNECT)
+ (should (eq (current-buffer)
+ (process-buffer erc-server-process)))
+ (current-buffer)))))
+ (erc-scenarios-common--join-network-id connect 'oofnet nil)))
+
+(ert-deftest erc-scenarios-join-netid--recon-ids ()
+ :tags '(:expensive-test)
+ (let ((connect (lambda ()
+ (with-current-buffer "oofnet"
+ (erc-cmd-RECONNECT)
+ (should (eq (current-buffer)
+ (process-buffer erc-server-process)))
+ (current-buffer)))))
+ (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
+
+;;; erc-scenarios-join-netid-recon-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-recon.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-recon.el
new file mode 100644
index 0000000000..be5230ef4a
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-join-netid-recon.el
@@ -0,0 +1,36 @@
+;;; erc-scenarios-join-netid-recon.el --- join-netid-recon scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--recon ()
+ :tags '(:expensive-test)
+ (let ((connect (lambda ()
+ (with-current-buffer "foonet"
+ (erc-cmd-RECONNECT)
+ (should (eq (current-buffer)
+ (process-buffer erc-server-process)))
+ (current-buffer)))))
+ (erc-scenarios-common--join-network-id connect nil nil)))
+
+;;; erc-scenarios-join-netid-recon.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-misc.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-misc.el
new file mode 100644
index 0000000000..22c6ac4fef
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-misc.el
@@ -0,0 +1,145 @@
+;;; erc-scenarios-misc.el --- Misc scenarios for ERC -*- lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+(ert-deftest erc-scenarios-base-flood ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/flood")
+ (erc-d-linger-secs 0.8)
+ (dumb-server (erc-d-run "localhost" t 'soju))
+ (port (process-contact dumb-server :service))
+ (erc-server-flood-penalty 0.5) ; this ratio MUST match
+ (erc-server-flood-margin 1.5) ; the default of 3:10
+ (expect (erc-d-t-make-expecter))
+ erc-autojoin-channels-alist)
+
+ (ert-info ("Connect to bouncer")
+ (with-current-buffer
+ (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (funcall expect 5 "Soju")))
+
+ (ert-info ("#chan@foonet exists")
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/foonet"))
+ (erc-d-t-search-for 2 "<bob/foonet>")
+ (erc-d-t-absent-for 0.1 "<joe")
+ (funcall expect 3 "was created on")))
+
+ (ert-info ("#chan@barnet exists")
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/barnet"))
+ (erc-d-t-search-for 2 "<joe/barnet>")
+ (erc-d-t-absent-for 0.1 "<bob")
+ (funcall expect 3 "was created on")
+ (funcall expect 5 "To get good guard")))
+
+ (ert-info ("Message not held in queue limbo")
+ (with-current-buffer "#chan/foonet"
+ ;; Without 'no-penalty param in `erc-server-send', should fail
+ ;; after ~10 secs with:
+ ;;
+ ;; (erc-d-timeout "Timed out awaiting request: (:name ~privmsg
+ ;; :pattern \\`PRIVMSG #chan/foonet :alice: hi :timeout 2
+ ;; :dialog soju)")
+ ;;
+ ;; Try reversing commit and spying on queue interactively
+ (erc-cmd-MSG "#chan/foonet alice: hi")
+ (funcall expect 5 "tester: Good, very good")))
+
+ (ert-info ("All output sent")
+ (with-current-buffer "#chan/foonet"
+ (funcall expect 8 "Some man or other"))
+ (with-current-buffer "#chan/barnet"
+ (while (accept-process-output erc-server-process))
+ (funcall expect 5 "That's he that was Othello")))))
+
+;; Corner case demoing fallback behavior for an absent 004 RPL but a
+;; present 422 or 375. If this is unlikely enough, remove or guard
+;; with `ert-skip' plus some condition so it only runs when explicitly
+;; named via ERT specifier
+
+(ert-deftest erc-scenarios-networks-announced-missing ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "networks/announced-missing")
+ (erc-d-linger-secs 0.5)
+ (expect (erc-d-t-make-expecter))
+ (dumb-server (erc-d-run "localhost" t 'foonet))
+ (port (process-contact dumb-server :service)))
+
+ (ert-info ("Connect without password")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (let ((err (should-error (sleep-for 1))))
+ (should (string-match-p "Failed to determine" (cadr err))))
+ (funcall expect 1 "Failed to determine")
+ (funcall expect 1 "Failed to determine")
+ (should-not erc-network)
+ (should (string= erc-server-announced-name "irc.foonet.org"))))))
+
+;; Targets that are host/server masks like $*, $$*, and #* are routed
+;; to the server buffer: https://github.com/ircdocs/wooooms/issues/5
+
+(ert-deftest erc-scenarios-base-mask-target-routing ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/mask-target-routing")
+ (erc-d-linger-secs 0.5)
+ (dumb-server (erc-d-run "localhost" t 'foonet))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter)))
+
+ (ert-info ("Connect to foonet")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+ (erc-d-t-wait-for 10 (get-buffer "foonet"))
+
+ (ert-info ("Channel buffer #foo playback received")
+ (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#foo"))
+ (funcall expect 10 "Excellent workman")))
+
+ (ert-info ("Global notices routed to server buffer")
+ (with-current-buffer "foonet"
+ (funcall expect 10 "going down soon")
+ (funcall expect 10 "this is a warning")
+ (funcall expect 10 "second warning")
+ (funcall expect 10 "final warning")))
+
+ (should-not (get-buffer "$*"))))
+
+;;; erc-scenarios-misc.el ends here
diff --git a/test/lisp/erc/erc-scenarios/erc-scenarios-services-misc.el
b/test/lisp/erc/erc-scenarios/erc-scenarios-services-misc.el
new file mode 100644
index 0000000000..07c8f1ef7a
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/erc-scenarios-services-misc.el
@@ -0,0 +1,86 @@
+;;; erc-scenarios-services-misc.el --- Services-misc scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join)
+ (require 'erc-services))
+
+(ert-deftest erc-scenarios-services-password ()
+ :tags '(:expensive-test)
+
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "services/password")
+ (erc-server-flood-penalty 0.1)
+ (erc-modules (cons 'services erc-modules))
+ (erc-nickserv-passwords '((Libera.Chat (("joe" . "bar")
+ ("tester" . "changeme")))))
+ (expect (erc-d-t-make-expecter))
+ (dumb-server (erc-d-run "localhost" t 'libera))
+ (port (process-contact dumb-server :service)))
+
+ (ert-info ("Connect without password")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (erc-d-t-wait-for 5 (eq erc-network 'Libera.Chat))
+ (funcall expect 5 "This nickname is registered.")
+ (funcall expect 2 "You are now identified")
+ (funcall expect 1 "Last login from")
+ (erc-cmd-QUIT "")))
+
+ (erc-services-mode -1)
+
+ (should-not (memq 'services erc-modules))))
+
+(ert-deftest erc-scenarios-services-prompt ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "services/password")
+ (erc-server-flood-penalty 0.1)
+ (inhibit-interaction nil)
+ (erc-modules (cons 'services erc-modules))
+ (expect (erc-d-t-make-expecter))
+ (dumb-server (erc-d-run "localhost" t 'libera))
+ (port (process-contact dumb-server :service)))
+
+ (ert-info ("Connect without password")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :full-name "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (ert-simulate-keys "changeme\r"
+ (erc-d-t-wait-for 10 (eq erc-network 'Libera.Chat))
+ (funcall expect 3 "This nickname is registered.")
+ (funcall expect 3 "You are now identified")
+ (funcall expect 3 "Last login from"))
+ (erc-cmd-QUIT "")))
+
+ (erc-services-mode -1)
+
+ (should-not (memq 'services erc-modules))))
+
+;;; erc-scenarios-services-misc.el ends here
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/bouncer-history/barnet.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/bouncer-history/barnet.eld
similarity index 99%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/bouncer-history/barnet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/bouncer-history/barnet.eld
index 9a8408ad6a..4b6ccfff38 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/bouncer-history/barnet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/bouncer-history/barnet.eld
@@ -1,5 +1,5 @@
;; -*- mode: lisp-data; -*-
-((pass 2 "PASS :barnet:changeme"))
+((pass 3 "PASS :barnet:changeme"))
((nick 1 "NICK tester"))
((user 1 "USER user 0 * :tester")
(0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/bouncer-history/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/bouncer-history/foonet.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/bouncer-history/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/bouncer-history/foonet.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/multi-net/barnet.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/multi-net/barnet.eld
similarity index 99%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/multi-net/barnet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/multi-net/barnet.eld
index 9aa2f2821c..c62a22a11c 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/multi-net/barnet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/multi-net/barnet.eld
@@ -18,7 +18,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 8 "MODE tester +i")
(0 ":irc.barnet.org 221 tester +i")
(0 ":irc.barnet.org NOTICE tester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/multi-net/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/multi-net/foonet.eld
similarity index 99%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/multi-net/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/multi-net/foonet.eld
index 79661a0fd2..f30b7deca1 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/multi-net/foonet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/multi-net/foonet.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 8 "MODE tester +i")
(0 ":irc.foonet.org 221 tester +i")
(0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked-again.eld
similarity index 97%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked-again.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked-again.eld
index c533d19dc1..ab3c7b0621 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked-again.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked-again.eld
@@ -4,7 +4,7 @@
(0.0 ":irc.foonet.org 433 * tester :Nickname is reserved by a different
account")
(0.0 ":irc.foonet.org FAIL NICK NICKNAME_RESERVED tester :Nickname is
reserved by a different account"))
-((nick 1 "NICK tester`")
+((nick 3 "NICK tester`")
(0.1 ":irc.foonet.org 001 tester` :Welcome to the foonet IRC Network tester`")
(0.0 ":irc.foonet.org 002 tester` :Your host is irc.foonet.org, running
version oragono-2.6.1-937b9b02368748e5")
(0.0 ":irc.foonet.org 003 tester` :This server was created Fri, 24 Sep 2021
01:38:36 UTC")
@@ -21,7 +21,7 @@
(0.2 ":irc.foonet.org 266 tester` 3 3 :Current global users 3, max 3")
(0.0 ":irc.foonet.org 422 tester` :MOTD File is missing"))
-((mode-user 1.2 "MODE tester` +i")
+((mode-user 3.2 "MODE tester` +i")
(0.0 ":irc.foonet.org 221 tester` +i")
(0.0 ":irc.foonet.org NOTICE tester` :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked-foisted-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked-foisted-again.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked-foisted-again.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked-foisted-again.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked-foisted.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked-foisted.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked-foisted.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked-foisted.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked.eld
index c4aff9db5f..4e96fd7304 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/nick-bump/renicked.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/nick-bump/renicked.eld
@@ -17,7 +17,7 @@
(0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 12 "MODE tester +i")
(0.0 ":irc.foonet.org 221 tester +i")
(0.0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/reconnect-playback/foonet-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/reconnect-playback/foonet-again.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/reconnect-playback/foonet-again.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/reconnect-playback/foonet-again.eld
index 1eb633260c..4210c07e41 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/reconnect-playback/foonet-again.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/reconnect-playback/foonet-again.eld
@@ -17,7 +17,7 @@
(0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10 "MODE tester +i")
;; No mode answer
(0.0 ":tester!~u@mw6kegwt77kwe.irc JOIN #chan")
(0.0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
@@ -27,7 +27,7 @@
(0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:56] alice: With these
mortals on the ground.")
(0.0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete."))
-((mode 1 "MODE #chan")
+((mode 10 "MODE #chan")
(0.0 ":irc.foonet.org 324 tester #chan +nt")
(0.0 ":irc.foonet.org 329 tester #chan 1623816901")
(0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: My name, my good lord,
is Parolles.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/reconnect-playback/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/reconnect-playback/foonet.eld
similarity index 97%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/reconnect-playback/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/reconnect-playback/foonet.eld
index 347e565498..6f50ecca4e 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/reconnect-playback/foonet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/reconnect-playback/foonet.eld
@@ -17,7 +17,7 @@
(0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 5 "MODE tester +i")
;; No mode answer
(0.0 ":irc.znc.in 306 tester :You have been marked as being away")
(0.0 ":tester!~u@mw6kegwt77kwe.irc JOIN #chan")
@@ -33,7 +33,7 @@
(0.0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
(0.0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
-((mode 1 "MODE #chan")
+((mode 3 "MODE #chan")
(1.0 ":irc.foonet.org 324 tester #chan +nt")
(0.0 ":irc.foonet.org 329 tester #chan 1623816901")
(0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: At thy good heart's
oppression.")
@@ -47,6 +47,6 @@
(0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: And at my suit, sweet,
pardon what is past.")
(0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: My lord, you give me
most egregious indignity."))
-((quit 1 "QUIT :\2ERC\2"))
+((quit 2 "QUIT :\2ERC\2"))
((drop 0 DROP))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/same-network/chester.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/same-network/chester.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/same-network/chester.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/same-network/chester.eld
index e51cc590b0..f1aed2836c 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/same-network/chester.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/same-network/chester.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
(0 ":irc.foonet.org 422 chester :MOTD File is missing"))
-((mode-user 2.2 "MODE chester +i")
+((mode-user 12 "MODE chester +i")
(0 ":irc.foonet.org 221 chester +i")
(0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
(0 ":irc.foonet.org 353 chester = #chan :tester chester @alice bob")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/same-network/tester-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/same-network/tester-again.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/same-network/tester-again.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/same-network/tester-again.eld
index 1fb0a63ad6..67c3a94a26 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/same-network/tester-again.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/same-network/tester-again.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 2.2 "MODE tester +i")
+((mode-user 4.2 "MODE tester +i")
(0 ":irc.foonet.org 221 tester +i")
(0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect.")
(0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/association/same-network/tester.eld
b/test/lisp/erc/erc-scenarios/resources/base/association/same-network/tester.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/association/same-network/tester.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/association/same-network/tester.eld
index 333658fe94..cd9cacbe5d 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/association/same-network/tester.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/association/same-network/tester.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 2.2 "MODE tester +i")
+((mode-user 12 "MODE tester +i")
(0 ":irc.foonet.org 221 tester +i")
(0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git a/test/lisp/erc/erc-scenarios-resources/base/auth-source/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/auth-source/foonet.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/auth-source/foonet.eld
rename to test/lisp/erc/erc-scenarios/resources/base/auth-source/foonet.eld
diff --git a/test/lisp/erc/erc-scenarios-resources/base/auth-source/nopass.eld
b/test/lisp/erc/erc-scenarios/resources/base/auth-source/nopass.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/auth-source/nopass.eld
rename to test/lisp/erc/erc-scenarios/resources/base/auth-source/nopass.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/channel-buffer-revival/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/channel-buffer-revival/foonet.eld
similarity index 99%
rename from
test/lisp/erc/erc-scenarios-resources/base/channel-buffer-revival/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/channel-buffer-revival/foonet.eld
index cc719d275f..b09692327c 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/channel-buffer-revival/foonet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/channel-buffer-revival/foonet.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 3.2 "MODE tester +i")
+((mode-user 12 "MODE tester +i")
(0 ":irc.foonet.org 221 tester +i")
(0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git a/test/lisp/erc/erc-scenarios-resources/base/flood/soju.eld
b/test/lisp/erc/erc-scenarios/resources/base/flood/soju.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/flood/soju.eld
rename to test/lisp/erc/erc-scenarios/resources/base/flood/soju.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/gapless-connect/barnet.eld
b/test/lisp/erc/erc-scenarios/resources/base/gapless-connect/barnet.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/gapless-connect/barnet.eld
rename to test/lisp/erc/erc-scenarios/resources/base/gapless-connect/barnet.eld
index a819e81775..4e658802ef 100644
--- a/test/lisp/erc/erc-scenarios-resources/base/gapless-connect/barnet.eld
+++ b/test/lisp/erc/erc-scenarios/resources/base/gapless-connect/barnet.eld
@@ -16,7 +16,7 @@
(0 ":irc.barnet.org 266 tester 1 1 :Current global users 1, max 1")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 3.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@8cgjyczyrjgby.irc JOIN #bar")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/gapless-connect/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/gapless-connect/foonet.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/gapless-connect/foonet.eld
rename to test/lisp/erc/erc-scenarios/resources/base/gapless-connect/foonet.eld
index dc76a7307f..4ac4a3e596 100644
--- a/test/lisp/erc/erc-scenarios-resources/base/gapless-connect/foonet.eld
+++ b/test/lisp/erc/erc-scenarios/resources/base/gapless-connect/foonet.eld
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 3.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #foo")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/gapless-connect/pass-stub.eld
b/test/lisp/erc/erc-scenarios/resources/base/gapless-connect/pass-stub.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/gapless-connect/pass-stub.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/gapless-connect/pass-stub.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/mask-target-routing/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/mask-target-routing/foonet.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/mask-target-routing/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/mask-target-routing/foonet.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet-again.eld
similarity index 95%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet-again.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet-again.eld
index 62d17692cf..69ca50aab9 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet-again.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet-again.eld
@@ -1,7 +1,7 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :barnet:changeme"))
-((nick 1 "NICK tester"))
-((user 1 "USER user 0 * :tester")
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
(0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
(0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version
oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021
07:41:08 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 2.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer ^
(0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
@@ -38,7 +38,7 @@
((~join 3 "JOIN #chan"))
-((mode 2 "MODE #chan")
+((mode 5 "MODE #chan")
(0 ":irc.barnet.org 324 tester #chan +nt")
(0 ":irc.barnet.org 329 tester #chan 1620805269")
(0.1 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defence, by
mercy, 'tis most just.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet-drop.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet-drop.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet-drop.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet-drop.eld
index 9b5edd6208..dff88f3a8d 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet-drop.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet-drop.eld
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer ^
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet.eld
similarity index 94%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet.eld
index 720e7cf8c8..abfcc6ed48 100644
--- a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/barnet.eld
+++ b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/barnet.eld
@@ -1,7 +1,7 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :barnet:changeme"))
-((nick 1 "NICK tester"))
-((user 1 "USER user 0 * :tester")
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
(0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
(0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version
oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021
07:41:08 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer ^
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
@@ -29,7 +29,7 @@
(0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!")
(0 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!"))
-((mode 1 "MODE #chan")
+((mode 3 "MODE #chan")
(0 ":irc.barnet.org 324 tester #chan +nt")
(0 ":irc.barnet.org 329 tester #chan 1620805269")
(0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: But you have outfaced
them all.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet-again.eld
similarity index 97%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet-again.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet-again.eld
index b99beafc4b..c74dcb585f 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet-again.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet-again.eld
@@ -1,7 +1,7 @@
;; -*- mode: lisp-data; -*-
((pass 3 "PASS :foonet:changeme"))
-((nick 1 "NICK tester"))
-((user 1 "USER user 0 * :tester")
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
(0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
(0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version
oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021
07:41:09 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 2.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer ^
(0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
(0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
@@ -38,7 +38,7 @@
((~join 3 "JOIN #chan"))
-((mode 3 "MODE #chan")
+((mode 8 "MODE #chan")
(0 ":irc.foonet.org 324 tester #chan +nt")
(0 ":irc.foonet.org 329 tester #chan 1620805271")
(0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies,
in single blessedness.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet-drop.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet-drop.eld
similarity index 99%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet-drop.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet-drop.eld
index 630742603e..e3c41e2133 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet-drop.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet-drop.eld
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer ^
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet.eld
similarity index 95%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet.eld
index 4bbef6abc7..c241c59bb8 100644
--- a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/foonet.eld
+++ b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/foonet.eld
@@ -1,7 +1,7 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :foonet:changeme"))
-((nick 1 "NICK tester"))
-((user 1 "USER user 0 * :tester")
+((pass 3 "PASS :foonet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
(0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
(0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version
oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021
07:41:09 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 4.2 "MODE tester +i")
;; No mode answer ^
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
@@ -29,7 +29,7 @@
(0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!")
(0 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!"))
-((mode 1 "MODE #chan")
+((mode 3 "MODE #chan")
(0 ":irc.foonet.org 324 tester #chan +nt")
(0 ":irc.foonet.org 329 tester #chan 1620805271")
(0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: He cannot be heard of.
Out of doubt he is transported.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/stub-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/stub-again.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/bouncer/stub-again.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/bouncer/stub-again.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/same-network/chester.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/same-network/chester.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/same-network/chester.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/same-network/chester.eld
index 2cdc1f263f..8c2448733c 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/network-id/same-network/chester.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/network-id/same-network/chester.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
(0 ":irc.foonet.org 422 chester :MOTD File is missing"))
-((mode-user 1.2 "MODE chester +i")
+((mode-user 10.2 "MODE chester +i")
(0 ":irc.foonet.org 221 chester +i")
(0 ":irc.foonet.org NOTICE chester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/network-id/same-network/tester.eld
b/test/lisp/erc/erc-scenarios/resources/base/network-id/same-network/tester.eld
similarity index 99%
rename from
test/lisp/erc/erc-scenarios-resources/base/network-id/same-network/tester.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/network-id/same-network/tester.eld
index 38e505a101..76312a7a14 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/network-id/same-network/tester.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/network-id/same-network/tester.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
(0 ":irc.foonet.org 221 tester +i")
(0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is
logging all user I/O. If you do not wish for everything you send to be readable
by the server owner(s), please disconnect."))
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/reconnect/aborted-dupe.eld
b/test/lisp/erc/erc-scenarios/resources/base/reconnect/aborted-dupe.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/reconnect/aborted-dupe.eld
rename to test/lisp/erc/erc-scenarios/resources/base/reconnect/aborted-dupe.eld
diff --git a/test/lisp/erc/erc-scenarios-resources/base/reconnect/aborted.eld
b/test/lisp/erc/erc-scenarios/resources/base/reconnect/aborted.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/reconnect/aborted.eld
rename to test/lisp/erc/erc-scenarios/resources/base/reconnect/aborted.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/reconnect/options-again.eld
b/test/lisp/erc/erc-scenarios/resources/base/reconnect/options-again.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/reconnect/options-again.eld
rename to test/lisp/erc/erc-scenarios/resources/base/reconnect/options-again.eld
diff --git a/test/lisp/erc/erc-scenarios-resources/base/reconnect/options.eld
b/test/lisp/erc/erc-scenarios/resources/base/reconnect/options.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/reconnect/options.eld
rename to test/lisp/erc/erc-scenarios/resources/base/reconnect/options.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/reconnect/timer-last.eld
b/test/lisp/erc/erc-scenarios/resources/base/reconnect/timer-last.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/reconnect/timer-last.eld
rename to test/lisp/erc/erc-scenarios/resources/base/reconnect/timer-last.eld
diff --git a/test/lisp/erc/erc-scenarios-resources/base/reconnect/timer.eld
b/test/lisp/erc/erc-scenarios/resources/base/reconnect/timer.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/reconnect/timer.eld
rename to test/lisp/erc/erc-scenarios/resources/base/reconnect/timer.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/renick/queries/bouncer-barnet.eld
b/test/lisp/erc/erc-scenarios/resources/base/renick/queries/bouncer-barnet.eld
similarity index 96%
rename from
test/lisp/erc/erc-scenarios-resources/base/renick/queries/bouncer-barnet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/renick/queries/bouncer-barnet.eld
index 9755920f37..fc6cdaafe9 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/renick/queries/bouncer-barnet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/renick/queries/bouncer-barnet.eld
@@ -1,7 +1,7 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :barnet:changeme"))
-((nick 1 "NICK tester"))
-((user 1 "USER user 0 * :tester")
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
(0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
(0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version
oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.barnet.org 003 tester :This server was created Tue, 01 Jun 2021
07:49:23 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 3.2 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@286u8jcpis84e.irc JOIN #chan")
@@ -32,7 +32,7 @@
(0 ":irc.barnet.org NOTICE tester :[09:13:24] This server is in debug mode
and is logging all user I/O. If you do not wish for everything you send to be
readable by the server owner(s), please disconnect.")
(0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
-((mode 1 "MODE #chan")
+((mode 5 "MODE #chan")
(0 ":irc.barnet.org 324 tester #chan +nt")
(0 ":irc.barnet.org 329 tester #chan 1622538742")
(0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: By favours several which
they did bestow.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/renick/queries/bouncer-foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/renick/queries/bouncer-foonet.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/renick/queries/bouncer-foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/renick/queries/bouncer-foonet.eld
index 0af67935a5..2da538afd9 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/renick/queries/bouncer-foonet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/renick/queries/bouncer-foonet.eld
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 5.2 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@u4mvbswyw8gbg.irc JOIN #chan")
@@ -32,7 +32,7 @@
(0 ":irc.foonet.org NOTICE tester :[09:12:53] This server is in debug mode
and is logging all user I/O. If you do not wish for everything you send to be
readable by the server owner(s), please disconnect.")
(0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
-((mode 1 "MODE #chan")
+((mode 10 "MODE #chan")
(0 ":irc.foonet.org 324 tester #chan +nt")
(0 ":irc.foonet.org 329 tester #chan 1622538742")
(0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: When there is nothing
living but thee, thou shalt be welcome. I had rather be a beggar's dog than
Apemantus.")
diff --git a/test/lisp/erc/erc-scenarios-resources/base/renick/queries/solo.eld
b/test/lisp/erc/erc-scenarios/resources/base/renick/queries/solo.eld
similarity index 99%
rename from test/lisp/erc/erc-scenarios-resources/base/renick/queries/solo.eld
rename to test/lisp/erc/erc-scenarios/resources/base/renick/queries/solo.eld
index b3189871aa..12fa7d264e 100644
--- a/test/lisp/erc/erc-scenarios-resources/base/renick/queries/solo.eld
+++ b/test/lisp/erc/erc-scenarios/resources/base/renick/queries/solo.eld
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 8 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@gq7yjr7gsu7nn.irc JOIN #foo")
diff --git a/test/lisp/erc/erc-scenarios-resources/base/renick/self/auto.eld
b/test/lisp/erc/erc-scenarios/resources/base/renick/self/auto.eld
similarity index 98%
rename from test/lisp/erc/erc-scenarios-resources/base/renick/self/auto.eld
rename to test/lisp/erc/erc-scenarios/resources/base/renick/self/auto.eld
index 5b9c26738d..851db7f1cf 100644
--- a/test/lisp/erc/erc-scenarios-resources/base/renick/self/auto.eld
+++ b/test/lisp/erc/erc-scenarios/resources/base/renick/self/auto.eld
@@ -25,7 +25,7 @@
(0 ":irc.foonet.org 372 dummy :- Please visit us in #libera for questions and
support.")
(0 ":irc.foonet.org 376 dummy :End of /MOTD command."))
-((mode-user 1.2 "MODE dummy +i")
+((mode-user 10.2 "MODE dummy +i")
(0 ":dummy!~u@gq7yjr7gsu7nn.irc MODE dummy :+RZi")
(0 ":irc.znc.in 306 dummy :You have been marked as being away")
(0 ":dummy!~u@gq7yjr7gsu7nn.irc JOIN #foo")
@@ -39,7 +39,7 @@
(0 ":irc.foonet.org NOTICE dummy :[09:56:57] This server is in debug mode and
is logging all user I/O. If you do not wish for everything you send to be
readable by the server owner(s), please disconnect.")
(0 ":irc.foonet.org 305 dummy :You are no longer marked as being away"))
-((mode 1 "MODE #foo")
+((mode 10 "MODE #foo")
(0 ":irc.foonet.org 324 dummy #foo +nt")
(0 ":irc.foonet.org 329 dummy #foo 1622454985")
(0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady:
you must hold the credit of your father.")
diff --git a/test/lisp/erc/erc-scenarios-resources/base/renick/self/manual.eld
b/test/lisp/erc/erc-scenarios/resources/base/renick/self/manual.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/base/renick/self/manual.eld
rename to test/lisp/erc/erc-scenarios/resources/base/renick/self/manual.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/renick/self/qual-chester.eld
b/test/lisp/erc/erc-scenarios/resources/base/renick/self/qual-chester.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/renick/self/qual-chester.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/renick/self/qual-chester.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/renick/self/qual-tester.eld
b/test/lisp/erc/erc-scenarios/resources/base/renick/self/qual-tester.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/base/renick/self/qual-tester.eld
rename to test/lisp/erc/erc-scenarios/resources/base/renick/self/qual-tester.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/channel-buffers/barnet.eld
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/channel-buffers/barnet.eld
similarity index 97%
rename from
test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/channel-buffers/barnet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/channel-buffers/barnet.eld
index c90c399aed..82700c5912 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/channel-buffers/barnet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/channel-buffers/barnet.eld
@@ -1,7 +1,7 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :barnet:changeme"))
-((nick 1 "NICK tester"))
-((user 1 "USER user 0 * :tester")
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
(0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
(0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version
oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.barnet.org 003 tester :This server was created Wed, 05 May 2021
09:05:33 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@wvys46tx8tpmk.irc JOIN #chan")
@@ -34,7 +34,7 @@
(0 ":irc.barnet.org NOTICE tester :[09:05:35] This server is in debug mode
and is logging all user I/O. If you do not wish for everything you send to be
readable by the server owner(s), please disconnect.")
(0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
-((mode 1 "MODE #chan")
+((mode 3 "MODE #chan")
(0 ":irc.barnet.org 324 tester #chan +nt")
(0 ":irc.barnet.org 329 tester #chan 1620205534")
(0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: That will be given to
the loudest noise we make.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/channel-buffers/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/channel-buffers/foonet.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/channel-buffers/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/channel-buffers/foonet.eld
index 648321875b..a11cfac2e7 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/channel-buffers/foonet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/channel-buffers/foonet.eld
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 12 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@247eaxkrufj44.irc JOIN #chan")
@@ -34,7 +34,7 @@
(0 ":irc.foonet.org NOTICE tester :[09:06:05] This server is in debug mode
and is logging all user I/O. If you do not wish for everything you send to be
readable by the server owner(s), please disconnect.")
(0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
-((mode 1 "MODE #chan")
+((mode 10 "MODE #chan")
(0 ":irc.foonet.org 324 tester #chan +nt")
(0 ":irc.foonet.org 329 tester #chan 1620205534")
(0.5 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: Nor I no strength to
climb without thy help.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/server-buffers/barnet.eld
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/server-buffers/barnet.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/server-buffers/barnet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/server-buffers/barnet.eld
index 2c4264c746..cc7aff1007 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/server-buffers/barnet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/server-buffers/barnet.eld
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":irc.barnet.org NOTICE tester :[11:29:00] This server is in debug mode
and is logging all user I/O. If you do not wish for everything you send to be
readable by the server owner(s), please disconnect.")
diff --git
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/server-buffers/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/server-buffers/foonet.eld
similarity index 98%
rename from
test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/server-buffers/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/server-buffers/foonet.eld
index 2a8418eecf..3a84610846 100644
---
a/test/lisp/erc/erc-scenarios-resources/base/reuse-buffers/server-buffers/foonet.eld
+++
b/test/lisp/erc/erc-scenarios/resources/base/reuse-buffers/server-buffers/foonet.eld
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":irc.foonet.org NOTICE tester :[11:29:00] This server is in debug mode
and is logging all user I/O. If you do not wish for everything you send to be
readable by the server owner(s), please disconnect.")
diff --git a/test/lisp/erc/erc-d/erc-d-i.el
b/test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-i.el
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-i.el
rename to test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-i.el
diff --git a/test/lisp/erc/erc-d/erc-d-t.el
b/test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-t.el
similarity index 97%
rename from test/lisp/erc/erc-d/erc-d-t.el
rename to test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-t.el
index 97231a3755..eebb0f1e2c 100644
--- a/test/lisp/erc/erc-d/erc-d-t.el
+++ b/test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-t.el
@@ -21,10 +21,11 @@
;;; Commentary:
;;; Code:
-(eval-and-compile (let ((dir (getenv "EMACS_TEST_DIRECTORY")))
- (when dir
- (load (concat dir "/lisp/erc/erc-d/erc-d-u") nil t))))
-(require 'erc-d-u)
+(eval-and-compile
+ (let* ((d (file-name-directory (or (macroexp-file-name) buffer-file-name)))
+ (load-path (cons (directory-file-name d) load-path)))
+ (require 'erc-d-u)))
+
(require 'ert)
(defun erc-d-t-kill-related-buffers ()
diff --git a/test/lisp/erc/erc-d/erc-d-u.el
b/test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-u.el
similarity index 99%
rename from test/lisp/erc/erc-d/erc-d-u.el
rename to test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-u.el
index 187ee272d1..0c834c8714 100644
--- a/test/lisp/erc/erc-d/erc-d-u.el
+++ b/test/lisp/erc/erc-scenarios/resources/erc-d/erc-d-u.el
@@ -109,7 +109,7 @@
(defvar erc-d-u--library-directory (file-name-directory load-file-name))
(defvar erc-d-u-canned-dialog-dir
- (file-name-as-directory (expand-file-name "erc-d-self-resources"
+ (file-name-as-directory (expand-file-name "resources"
erc-d-u--library-directory)))
(defun erc-d-u--normalize-canned-name (dialog)
diff --git a/test/lisp/erc/erc-d/erc-d.el
b/test/lisp/erc/erc-scenarios/resources/erc-d/erc-d.el
similarity index 98%
rename from test/lisp/erc/erc-d/erc-d.el
rename to test/lisp/erc/erc-scenarios/resources/erc-d/erc-d.el
index b84e414548..857f6399f9 100644
--- a/test/lisp/erc/erc-d/erc-d.el
+++ b/test/lisp/erc/erc-scenarios/resources/erc-d/erc-d.el
@@ -68,7 +68,7 @@
;; flexibility. However, it's best to keep things simple (even if
;; overly verbose), so others can easily tell what's going on at a
;; glance. If necessary, consult existing tests for examples (grep
-;; for the variables `erc-d-spec-vars' and `erc-d-match-handlers').
+;; for the variables `erc-d-tmpl-vars' and `erc-d-match-handlers').
;;
;; Subprocess or in-process?:
;;
@@ -105,7 +105,7 @@
;;
;; * vars (alist of cons pairs); for sharing state among template
;; functions during the lifetime of an exchange. Initially populated
-;; by `erc-d-spec-vars', these KEY/VALUE pairs are made available in
+;; by `erc-d-tmpl-vars', these KEY/VALUE pairs are made available in
;; the template environment as bound variables. Updates can be made
;; by exchange handlers (see `erc-d-match-handlers'). When VALUE is a
;; function, occurrences of KEY in an outgoing spec are replaced with
@@ -122,13 +122,13 @@
;; - Maybe migrate d-u and d-i dependencies here
;;; Code:
-(eval-and-compile (let ((dir (getenv "EMACS_TEST_DIRECTORY")))
- (when dir
- (load (concat dir "/lisp/erc/erc-d/erc-d-i") nil t)
- (load (concat dir "/lisp/erc/erc-d/erc-d-u") nil t))))
+(eval-and-compile
+ (let* ((d (file-name-directory (or (macroexp-file-name) buffer-file-name)))
+ (load-path (cons (directory-file-name d) load-path)))
+ (require 'erc-d-i)
+ (require 'erc-d-u)))
+
(require 'ring)
-(require 'erc-d-i)
-(require 'erc-d-u)
(defvar erc-d-server-name "erc-d-server"
"Default name of a server process and basis for its buffer name.
@@ -144,7 +144,7 @@ dialog templates for the sender portion of a reply
message.")
For more granular control, use the provided LINGER `rx' variable (alone)
as the incoming template spec of a dialog's last exchange.")
-(defvar erc-d-spec-vars nil
+(defvar erc-d-tmpl-vars nil
"An alist of template bindings available to client dialogs.
Populate it when calling `erc-d-run', and the contents will be made
available to all client dialogs through the `erc-d-dialog' \"vars\"
@@ -163,7 +163,7 @@ event that an exchange-specific handler is needed, see
(defvar erc-d-match-handlers nil
"A plist of exchange-tag symbols mapped to request-handler functions.
-This is meant to address edge cases for which `erc-d-spec-vars' comes up
+This is meant to address edge cases for which `erc-d-tmpl-vars' comes up
short. These may include (1) needing access to the client process
itself and/or (2) adding or altering outgoing response templates before
rendering. Note that (2) requires using `erc-d-exchange-rebind' instead
@@ -918,12 +918,12 @@ process, otherwise sleep for the duration of the server
process.
A dialog must be a symbol matching the base name of a dialog file in
`erc-d-u-canned-dialog-dir'.
-The variable `erc-d-spec-vars' determines the common members of the
+The variable `erc-d-tmpl-vars' determines the common members of the
`erc-d--render-entries' ENTRIES param. Variables `erc-d-server-fqdn'
and `erc-d-linger-secs' determine the `erc-d-dialog' items
`:server-fqdn' and `:linger-secs' for all client processes.
-The variable `erc-d-spec-vars' can be used to initialize the
+The variable `erc-d-tmpl-vars' can be used to initialize the
process's `erc-d-dialog' vars item."
(when (and server-name (symbolp server-name))
(push server-name dialogs)
@@ -937,7 +937,7 @@ process's `erc-d-dialog' vars item."
(setq dialogs loaded))
(erc-d--start host service (or server-name erc-d-server-name)
:dialog-dialogs dialogs
- :dialog-vars erc-d-spec-vars
+ :dialog-vars erc-d-tmpl-vars
:dialog-linger-secs erc-d-linger-secs
:dialog-server-fqdn erc-d-server-fqdn
:dialog-match-handlers (erc-d-u--unkeyword
@@ -951,10 +951,9 @@ outgoing messages to standard out.
The main options are --host HOST and --port PORT, which default to
localhost and auto, respectively. The args are the dialogs to run.
-Unlike with `erc-d-run', dialogs here *must* be file paths, meaning
-Lisp-Data files adhering to the required format. (These consist of
-\"specs\" detailing timing and template info; see commentary for
-specifics.)
+Unlike with `erc-d-run', dialogs here *must* be files, meaning Lisp-Data
+files adhering to the required format. (These consist of \"specs\"
+detailing timing and template info; see commentary for specifics.)
An optional --add-time N option can also be passed to hike up timeouts
by some number of seconds N. For example, you might run:
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/basic.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/basic.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/basic.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/basic.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/depleted.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/depleted.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/depleted.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/depleted.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/drop-a.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/drop-a.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/drop-a.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/drop-a.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/drop-b.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/drop-b.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/drop-b.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/drop-b.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/dynamic-barnet.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic-barnet.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/dynamic-barnet.eld
rename to
test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic-barnet.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/dynamic-foonet.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic-foonet.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/dynamic-foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic-foonet.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/dynamic-stub.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic-stub.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/dynamic-stub.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic-stub.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/dynamic.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic.eld
similarity index 89%
rename from test/lisp/erc/erc-d/erc-d-self-resources/dynamic.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic.eld
index 8698560109..459b6e52bf 100644
--- a/test/lisp/erc/erc-d/erc-d-self-resources/dynamic.eld
+++ b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/dynamic.eld
@@ -1,8 +1,8 @@
;;; -*- mode: lisp-data -*-
((pass 10.0 "PASS " (? ?:) "changeme"))
-((nick 0.2 "NICK tester"))
+((nick 2.2 "NICK tester"))
-((user 0.2 "USER " user " " (ignored digit "*") " :" realname)
+((user 2.2 "USER " user " " (ignored digit "*") " :" realname)
(0.0 ":" dom " 001 " nick " :Welcome to the Internet Relay Network tester")
(0.0 ":" dom " 002 " nick " :Your host is " dom)
(0.0 ":" dom " 003 " nick " :This server was created just now")
@@ -18,7 +18,7 @@
(0.0 ":" dom " 266 " nick " 3 3 :Current global users 3, max 3")
(0.0 ":" dom " 422 " nick " :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 2.2 "MODE tester +i")
(0.0 ":" dom " 221 " nick " +Zi")
(0.0 ":" dom " 306 " nick " :You have been marked as being away")
@@ -26,5 +26,5 @@
(0.0 ":" dom " 353 alice = #chan :+alice!~alice@example.com
@%+bob!~bob@example.org")
(0.0 ":" dom " 366 alice #chan :End of NAMES list"))
-((mode 1.2 "MODE #chan")
+((mode 2.2 "MODE #chan")
(0.1 ":bob!~bob@example.org PRIVMSG #chan :" nick ": hey"))
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/eof.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/eof.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/eof.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/eof.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/fuzzy.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/fuzzy.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/fuzzy.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/fuzzy.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/incremental.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/incremental.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/incremental.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/incremental.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/irc-parser-tests.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/irc-parser-tests.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/irc-parser-tests.eld
rename to
test/lisp/erc/erc-scenarios/resources/erc-d/resources/irc-parser-tests.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/linger-multi-a.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/linger-multi-a.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/linger-multi-a.eld
rename to
test/lisp/erc/erc-scenarios/resources/erc-d/resources/linger-multi-a.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/linger-multi-b.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/linger-multi-b.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/linger-multi-b.eld
rename to
test/lisp/erc/erc-scenarios/resources/erc-d/resources/linger-multi-b.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/linger.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/linger.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/linger.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/linger.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/no-block.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/no-block.eld
similarity index 98%
rename from test/lisp/erc/erc-d/erc-d-self-resources/no-block.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/no-block.eld
index cd341dd192..1b1f396563 100644
--- a/test/lisp/erc/erc-d/erc-d-self-resources/no-block.eld
+++ b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/no-block.eld
@@ -52,4 +52,4 @@
((mode-bar 1.5 "MODE #bar")
(0.0 ":irc.example.org 324 tester #bar +HMfnrt 50:5h :10:5")
(0.0 ":irc.example.org 329 tester #bar :1602642829")
- (0.1 ":alice!~alice@example.com PRIVMSG #bar :hi"))
+ (0.1 ":alice!~alice@example.com PRIVMSG #bar :hi 123"))
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/no-match.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/no-match.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/no-match.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/no-match.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/no-pong.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/no-pong.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/no-pong.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/no-pong.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/nonstandard.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/nonstandard.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/nonstandard.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/nonstandard.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/proxy-barnet.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-barnet.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/proxy-barnet.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-barnet.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/proxy-foonet.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-foonet.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/proxy-foonet.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-foonet.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/proxy-solo.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-solo.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/proxy-solo.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-solo.eld
diff --git
a/test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-subprocess.el
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-subprocess.el
new file mode 100644
index 0000000000..fed6206a6a
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/proxy-subprocess.el
@@ -0,0 +1,45 @@
+;;; proxy-subprocess.el --- Example setup file for erc-d -*- lexical-binding:
t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;; Code:
+
+(defvar erc-d-tmpl-vars)
+
+(setq erc-d-tmpl-vars
+
+ (list
+ (cons 'fqdn (lambda (helper)
+ (let ((name (funcall helper :dialog-name)))
+ (funcall helper :set
+ (if (eq name 'proxy-foonet)
+ "irc.foo.net"
+ "irc.bar.net")))))
+
+ (cons 'net (lambda (helper)
+ (let ((name (funcall helper :dialog-name)))
+ (funcall helper :set
+ (if (eq name 'proxy-foonet)
+ "FooNet"
+ "BarNet")))))
+
+ (cons 'network '(group (+ alpha)))))
+
+;;; proxy-subprocess.el ends here
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/timeout.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/timeout.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/timeout.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/timeout.eld
diff --git a/test/lisp/erc/erc-d/erc-d-self-resources/unexpected.eld
b/test/lisp/erc/erc-scenarios/resources/erc-d/resources/unexpected.eld
similarity index 100%
rename from test/lisp/erc/erc-d/erc-d-self-resources/unexpected.eld
rename to test/lisp/erc/erc-scenarios/resources/erc-d/resources/unexpected.eld
diff --git a/test/lisp/erc/erc-scenarios/resources/erc-scenarios-common.el
b/test/lisp/erc/erc-scenarios/resources/erc-scenarios-common.el
new file mode 100644
index 0000000000..0237c3e862
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios/resources/erc-scenarios-common.el
@@ -0,0 +1,467 @@
+;;; erc-scenarios-common.el --- common helpers for ERC scenarios -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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
+;; <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These are e2e-ish test cases primarily intended to assert core,
+;; fundamental behavior expected of any modern IRC client. Tests may
+;; also simulate specific scenarios drawn from bug reports. Incoming
+;; messages are provided by playback scripts resembling I/O logs. In
+;; place of time stamps, they have time deltas, which are used to
+;; govern the test server in a fashion reminiscent of music rolls (or
+;; the script(1) UNIX program). These scripts can be found in the
+;; other directories under test/lisp/erc/erc-scenarios/resources.
+;;
+;; Isolation:
+;;
+;; The set of enabled modules is shared among all tests. The function
+;; `erc-update-modules' activates them (as minor modes), but it never
+;; deactivates them. So there's no going back, and let-binding
+;; `erc-modules' is useless. The safest route is therefore to (1)
+;; assume the set of default modules is already activated or will be
+;; over the course of the test session and (2) let-bind relevant user
+;; options as needed. For example, to limit the damage of
+;; `erc-autojoin-channels-alist' to a given test, assume the
+;; `erc-join' library has already been loaded or will be on the next
+;; call to `erc-open'. And then just let-bind
+;; `erc-autojoin-channels-alist' for the duration of the test.
+;;
+;; Playing nice:
+;;
+;; Right now, these tests all rely on an ugly fixture macro named
+;; `erc-scenarios-common-with-cleanup', which is defined just below.
+;; It helps restore (but not really prepare) the environment by
+;; destroying any stray processes or buffers named in the first
+;; argument, a `let*'-style VAR-LIST. Relying on such a macro is
+;; unfortunate because in many ways it actually hampers readability by
+;; favoring magic over verbosity. But without it (or something
+;; similar), any failing test would cause all subsequent tests in this
+;; file to fail like dominoes (making all but the first backtrace
+;; useless).
+;;
+;; Misc:
+;;
+;; Note that in the following examples, nicknames Alice and Bob are
+;; always associated with the fake network FooNet, while nicks Joe and
+;; Mike are always on BarNet. (Networks are sometimes downcased.)
+;;
+;; XXX This file should *not* contain any test cases.
+
+;;; Code:
+
+(require 'ert-x) ; cl-lib
+(eval-and-compile
+ (let* ((d (expand-file-name ".." (ert-resource-directory)))
+ (load-path (cons (concat d "/erc-d") load-path)))
+ (require 'erc-d-t)
+ (require 'erc-d)))
+
+(require 'erc-backend)
+
+(eval-when-compile (require 'erc-join)
+ (require 'erc-services))
+
+(declare-function erc-network "erc-networks")
+(defvar erc-network)
+
+(defvar erc-scenarios-common--resources-dir
+ (expand-file-name "../" (ert-resource-directory)))
+
+;; Teardown is already inhibited when running interactively, which
+;; prevents subsequent tests from succeeding, so we might as well
+;; treat inspection as the goal.
+(unless noninteractive
+ (setq erc-server-auto-reconnect nil))
+
+(defvar erc-scenarios-common-dialog nil)
+(defvar erc-scenarios-common-extra-teardown nil)
+
+(defun erc-scenarios-common--add-silence ()
+ (advice-add #'erc-login :around #'erc-d-t-silence-around)
+ (advice-add #'erc-handle-login :around #'erc-d-t-silence-around)
+ (advice-add #'erc-server-connect :around #'erc-d-t-silence-around))
+
+(defun erc-scenarios-common--remove-silence ()
+ (advice-remove #'erc-login #'erc-d-t-silence-around)
+ (advice-remove #'erc-handle-login #'erc-d-t-silence-around)
+ (advice-remove #'erc-server-connect #'erc-d-t-silence-around))
+
+(defun erc-scenarios-common--print-trace ()
+ (when (and (boundp 'trace-buffer) (get-buffer trace-buffer))
+ (with-current-buffer trace-buffer
+ (message "%S" (buffer-string))
+ (kill-buffer))))
+
+(eval-and-compile
+ (defun erc-scenarios-common--make-bindings (bindings)
+ `((erc-d-u-canned-dialog-dir (expand-file-name
+ (or erc-scenarios-common-dialog
+ (cadr (assq 'erc-scenarios-common-dialog
+ ',bindings)))
+ erc-scenarios-common--resources-dir))
+ (erc-d-tmpl-vars `(,@erc-d-tmpl-vars
+ (quit . ,(erc-quit/part-reason-default))
+ (erc-version . ,erc-version)))
+ (erc-modules (copy-sequence erc-modules))
+ (inhibit-interaction t)
+ (auth-source-do-cache nil)
+ (erc-auth-source-parameters-join-function nil)
+ (erc-autojoin-channels-alist nil)
+ (erc-server-auto-reconnect nil)
+ ,@bindings)))
+
+(defmacro erc-scenarios-common-with-cleanup (bindings &rest body)
+ "Provide boilerplate cleanup tasks after calling BODY with BINDINGS.
+
+If an `erc-d' process exists, wait for it to start before running BODY.
+If `erc-autojoin-mode' mode is bound, restore it during cleanup if
+disabled by BODY. Other defaults common to these test cases are added
+below and can be overridden, except when wanting the \"real\" default
+value, which must be looked up or captured outside of the calling form.
+
+Dialog resource directories are located by expanding the variable
+`erc-scenarios-common-dialog' or its value in BINDINGS."
+ (declare (indent 1))
+
+ (let* ((orig-autojoin-mode (make-symbol "orig-autojoin-mode"))
+ (combind `((,orig-autojoin-mode (bound-and-true-p erc-autojoin-mode))
+ ,@(erc-scenarios-common--make-bindings bindings))))
+
+ `(erc-d-t-with-cleanup (,@combind)
+
+ (ert-info ("Restore autojoin, etc., kill ERC buffers")
+ (dolist (buf (buffer-list))
+ (when-let ((erc-d-u--process-buffer)
+ (proc (get-buffer-process buf)))
+ (erc-d-t-wait-for 5 "Dumb server dies on its own"
+ (not (process-live-p proc)))))
+
+ (erc-scenarios-common--remove-silence)
+
+ (when erc-scenarios-common-extra-teardown
+ (ert-info ("Running extra teardown")
+ (funcall erc-scenarios-common-extra-teardown)))
+
+ (when (and (boundp 'erc-autojoin-mode)
+ (not (eq erc-autojoin-mode ,orig-autojoin-mode)))
+ (erc-autojoin-mode (if ,orig-autojoin-mode +1 -1)))
+
+ (when noninteractive
+ (erc-scenarios-common--print-trace)
+ (erc-d-t-kill-related-buffers)
+ (delete-other-windows)))
+
+ (erc-scenarios-common--add-silence)
+
+ (ert-info ("Wait for dumb server")
+ (dolist (buf (buffer-list))
+ (with-current-buffer buf
+ (when erc-d-u--process-buffer
+ (erc-d-t-search-for 3 "Starting")))))
+
+ (ert-info ("Activate erc-debug-irc-protocol")
+ (unless (and noninteractive (not erc-debug-irc-protocol))
+ (erc-toggle-debug-irc-protocol)))
+
+ ,@body)))
+
+(defun erc-scenarios-common-assert-initial-buf-name (id port)
+ ;; Assert no limbo period when explicit ID given
+ (should (string= (if id
+ (symbol-name id)
+ (format "127.0.0.1:%d" port))
+ (buffer-name))))
+
+(defun erc-scenarios-common-buflist (prefix)
+ "Return list of buffers with names sharing PREFIX."
+ (let (case-fold-search)
+ (erc-networks--id-sort-buffers
+ (delq nil
+ (mapcar (lambda (b)
+ (when (string-prefix-p prefix (buffer-name b)) b))
+ (buffer-list))))))
+
+;; This is more realistic than `erc-send-message' because it runs
+;; `erc-pre-send-functions', etc. Keyboard macros may be preferable,
+;; but they sometimes experience complications when an earlier test
+;; has failed.
+(defun erc-scenarios-common-say (str)
+ (goto-char erc-input-marker)
+ (insert str)
+ (erc-send-current-line))
+
+
+;;;; Fixtures
+
+(cl-defun erc-scenarios-common--base-network-id-bouncer
+ ((&key autop foo-id bar-id after
+ &aux
+ (foo-id (and foo-id 'oofnet))
+ (bar-id (and bar-id 'rabnet))
+ (serv-buf-foo (if foo-id "oofnet" "foonet"))
+ (serv-buf-bar (if bar-id "rabnet" "barnet"))
+ (chan-buf-foo (if foo-id "#chan@oofnet" "#chan@foonet"))
+ (chan-buf-bar (if bar-id "#chan@rabnet" "#chan@barnet")))
+ &rest dialogs)
+ "Ensure retired option `erc-rename-buffers' is now the default behavior.
+The option `erc-rename-buffers' is now deprecated and on by default, so
+this now just asserts baseline behavior. Originally from scenario
+clash-of-chans/rename-buffers as explained in Bug#48598: 28.0.50;
+buffer-naming collisions involving bouncers in ERC."
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/network-id/bouncer")
+ (erc-d-t-cleanup-sleep-secs 1)
+ (erc-server-flood-penalty 0.1)
+ (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (erc-server-auto-reconnect autop)
+ erc-server-buffer-foo erc-server-process-foo
+ erc-server-buffer-bar erc-server-process-bar)
+
+ (ert-info ("Connect to foonet")
+ (with-current-buffer
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"
+ :id foo-id))
+ (setq erc-server-process-foo erc-server-process)
+ (erc-scenarios-common-assert-initial-buf-name foo-id port)
+ (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+ (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-foo))
+ (funcall expect 5 "foonet")))
+
+ (ert-info ("Join #chan@foonet")
+ (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+ (funcall expect 5 "<alice>")))
+
+ (ert-info ("Connect to barnet")
+ (with-current-buffer
+ (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester"
+ :id bar-id))
+ (setq erc-server-process-bar erc-server-process)
+ (erc-scenarios-common-assert-initial-buf-name bar-id port)
+ (erc-d-t-wait-for 6 (eq (erc-network) 'barnet))
+ (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-bar))
+ (funcall expect 5 "barnet")))
+
+ (ert-info ("Server buffers are unique, no names based on IPs")
+ (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+ (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+ (ert-info ("Join #chan@barnet")
+ (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
+
+ (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
+ (equal (list (get-buffer chan-buf-bar)
+ (get-buffer chan-buf-foo))
+ (erc-scenarios-common-buflist "#chan")))
+
+ (ert-info ("#chan@<esid> is exclusive to foonet")
+ (with-current-buffer chan-buf-foo
+ (erc-d-t-search-for 1 "<bob>")
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (should (eq erc-server-process erc-server-process-foo))
+ (while (accept-process-output erc-server-process-foo))
+ (erc-d-t-search-for 1 "ape is dead")
+ (should-not (erc-server-process-alive))))
+
+ (ert-info ("#chan@<esid> is exclusive to barnet")
+ (with-current-buffer chan-buf-bar
+ (erc-d-t-search-for 1 "<joe>")
+ (erc-d-t-absent-for 0.1 "<bob>")
+ (should (eq erc-server-process erc-server-process-bar))
+ (while (accept-process-output erc-server-process-bar))
+ (erc-d-t-search-for 1 "keeps you from dishonour")
+ (should-not (erc-server-process-alive))))
+
+ (when after (funcall after))))
+
+(defun erc-scenarios-common--clash-rename-pass-handler (dialog exchange)
+ (when (eq (erc-d-dialog-name dialog) 'stub-again)
+ (let* ((match (erc-d-exchange-match exchange 1))
+ (sym (if (string= match "foonet") 'foonet-again 'barnet-again)))
+ (should (member match (list "foonet" "barnet")))
+ (erc-d-load-replacement-dialog dialog sym 1))))
+
+(defun erc-scenarios-common--base-network-id-bouncer--reconnect (foo-id bar-id)
+ (let ((erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+ (erc-d-match-handlers
+ ;; Auto reconnect is nondeterministic, so let computer decide
+ (list :pass #'erc-scenarios-common--clash-rename-pass-handler))
+ (after
+ (lambda ()
+ ;; Simulate disconnection and `erc-server-auto-reconnect'
+ (ert-info ("Reconnect to foonet and barnet back-to-back")
+ (with-current-buffer (if foo-id "oofnet" "foonet")
+ (erc-d-t-wait-for 5 (erc-server-process-alive)))
+ (with-current-buffer (if bar-id "rabnet" "barnet")
+ (erc-d-t-wait-for 5 (erc-server-process-alive))))
+
+ (ert-info ("#chan@foonet is exclusive to foonet")
+ (with-current-buffer (if foo-id "#chan@oofnet" "#chan@foonet")
+ (erc-d-t-search-for 1 "<alice>")
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (while (accept-process-output erc-server-process))
+ (erc-d-t-search-for 20 "please your lordship")))
+
+ (ert-info ("#chan@barnet is exclusive to barnet")
+ (with-current-buffer (if bar-id "#chan@rabnet" "#chan@barnet")
+ (erc-d-t-search-for 1 "<joe>")
+ (erc-d-t-absent-for 0.1 "<bob>")
+ (while (accept-process-output erc-server-process))
+ (erc-d-t-search-for 1 "much in private")))
+
+ ;; XXX this is important (reconnects overlapped, so we'd get
+ ;; chan@127.0.0.1:6667)
+ (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+ ;; Reconnection order doesn't matter here because session objects
+ ;; are persisted, meaning original timestamps preserved.
+ (should (equal (list (get-buffer (if bar-id "#chan@rabnet"
+ "#chan@barnet"))
+ (get-buffer (if foo-id "#chan@oofnet"
+ "#chan@foonet")))
+ (erc-scenarios-common-buflist "#chan"))))))
+ (erc-scenarios-common--base-network-id-bouncer
+ (list :autop t :foo-id foo-id :bar-id bar-id :after after)
+ 'foonet-drop 'barnet-drop
+ 'stub-again 'stub-again
+ 'foonet-again 'barnet-again)))
+
+;; XXX this is okay, but we also need to check that target buffers are
+;; already associated with a new process *before* a JOIN is sent by a
+;; server's playback burst. This doesn't do that.
+;;
+;; This *does* check that superfluous JOINs sent by the autojoin
+;; module are harmless when they're not acked (superfluous because the
+;; bouncer/server intitates the JOIN).
+
+(defun erc-scenarios-common--join-network-id (foo-reconnector foo-id bar-id)
+ "Ensure channels rejoined by erc-join.el DTRT.
+Originally from scenario clash-of-chans/autojoin as described in
+Bug#48598: 28.0.50; buffer-naming collisions involving bouncers in ERC."
+ (erc-scenarios-common-with-cleanup
+ ((chan-buf-foo (format "#chan@%s" (or foo-id "foonet")))
+ (chan-buf-bar (format "#chan@%s" (or bar-id "barnet")))
+ (erc-scenarios-common-dialog "join/network-id")
+ (erc-d-t-cleanup-sleep-secs 1)
+ (erc-server-flood-penalty 0.5)
+ (dumb-server (erc-d-run "localhost" t 'foonet 'barnet 'foonet-again))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ erc-server-buffer-foo erc-server-process-foo
+ erc-server-buffer-bar erc-server-process-bar)
+
+ (should (memq 'autojoin erc-modules))
+
+ (ert-info ("Connect to foonet")
+ (with-current-buffer
+ (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester"
+ :id foo-id))
+ (setq erc-server-process-foo erc-server-process)
+ (erc-scenarios-common-assert-initial-buf-name foo-id port)
+ (erc-d-t-wait-for 1 (eq (erc-network) 'foonet))
+ (funcall expect 5 "foonet")))
+
+ (ert-info ("Join #chan, find sentinel, quit")
+ (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+ (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+ (funcall expect 5 "vile thing")
+ (erc-cmd-QUIT "")))
+
+ (erc-d-t-wait-for 2 "Foonet connection deceased"
+ (not (erc-server-process-alive erc-server-buffer-foo)))
+
+ (should (equal erc-autojoin-channels-alist
+ (if foo-id '((oofnet "#chan")) '((foonet "#chan")))))
+
+ (ert-info ("Connect to barnet")
+ (with-current-buffer
+ (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester"
+ :id bar-id))
+ (setq erc-server-process-bar erc-server-process)
+ (erc-d-t-wait-for 5 (eq erc-network 'barnet))
+ (should (string= (buffer-name) (if bar-id "rabnet" "barnet")))))
+
+ (ert-info ("Server buffers are unique, no stray IP-based names")
+ (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+ (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+ (ert-info ("Only one #chan buffer exists")
+ (should (equal (list (get-buffer "#chan"))
+ (erc-scenarios-common-buflist "#chan"))))
+
+ (ert-info ("#chan is not auto-joined")
+ (with-current-buffer "#chan"
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (should-not (process-live-p erc-server-process))
+ (erc-d-t-ensure-for 0.1 "server buffer remains foonet"
+ (eq erc-server-process erc-server-process-foo))))
+
+ (with-current-buffer erc-server-buffer-bar
+ (erc-cmd-JOIN "#chan")
+ (erc-d-t-wait-for 3 (get-buffer chan-buf-foo))
+ (erc-d-t-wait-for 3 (get-buffer chan-buf-bar))
+ (with-current-buffer chan-buf-bar
+ (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-bar))
+ (funcall expect 5 "marry her instantly")))
+
+ (ert-info ("Reconnect to foonet")
+ (with-current-buffer (setq erc-server-buffer-foo
+ (funcall foo-reconnector))
+ (should (member (if foo-id '(oofnet "#chan") '(foonet "#chan"))
+ erc-autojoin-channels-alist))
+ (erc-d-t-wait-for 3 (erc-server-process-alive))
+ (setq erc-server-process-foo erc-server-process)
+ (erc-d-t-wait-for 2 (eq erc-network 'foonet))
+ (should (string= (buffer-name) (if foo-id "oofnet" "foonet")))
+ (funcall expect 5 "foonet")))
+
+ (ert-info ("#chan@foonet is clean, no cross-contamination")
+ (with-current-buffer chan-buf-foo
+ (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-foo))
+ (funcall expect 3 "<bob>")
+ (erc-d-t-absent-for 0.1 "<joe>")
+ (while (accept-process-output erc-server-process-foo))
+ (funcall expect 3 "not given me")))
+
+ (ert-info ("All #chan@barnet output received")
+ (with-current-buffer chan-buf-bar
+ (while (accept-process-output erc-server-process-bar))
+ (funcall expect 3 "hath an uncle here")))))
+
+(provide 'erc-scenarios-common)
+
+;;; erc-scenarios-common.el ends here
diff --git a/test/lisp/erc/erc-scenarios-resources/join/legacy/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/join/legacy/foonet.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/join/legacy/foonet.eld
rename to test/lisp/erc/erc-scenarios/resources/join/legacy/foonet.eld
diff --git a/test/lisp/erc/erc-scenarios-resources/join/network-id/barnet.eld
b/test/lisp/erc/erc-scenarios/resources/join/network-id/barnet.eld
similarity index 98%
rename from test/lisp/erc/erc-scenarios-resources/join/network-id/barnet.eld
rename to test/lisp/erc/erc-scenarios/resources/join/network-id/barnet.eld
index 1a13259383..e33dd6be29 100644
--- a/test/lisp/erc/erc-scenarios-resources/join/network-id/barnet.eld
+++ b/test/lisp/erc/erc-scenarios/resources/join/network-id/barnet.eld
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i"))
+((mode-user 12 "MODE tester +i"))
;; No mode answer
((join 2 "JOIN #chan")
diff --git
a/test/lisp/erc/erc-scenarios-resources/join/network-id/foonet-again.eld
b/test/lisp/erc/erc-scenarios/resources/join/network-id/foonet-again.eld
similarity index 97%
rename from
test/lisp/erc/erc-scenarios-resources/join/network-id/foonet-again.eld
rename to test/lisp/erc/erc-scenarios/resources/join/network-id/foonet-again.eld
index 08e50dc62b..b230eff27c 100644
--- a/test/lisp/erc/erc-scenarios-resources/join/network-id/foonet-again.eld
+++ b/test/lisp/erc/erc-scenarios/resources/join/network-id/foonet-again.eld
@@ -18,7 +18,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i")
+((mode-user 10.2 "MODE tester +i")
;; No mode answer ^
;; History
@@ -34,7 +34,7 @@
;; As a server, we ignore useless join sent by autojoin module
((~join 10 "JOIN #chan"))
-((mode-redux 1 "MODE #chan")
+((mode-redux 10 "MODE #chan")
(0 ":irc.foonet.org 324 tester #chan +nt")
(0 ":irc.foonet.org 329 tester #chan 1620608304")
(0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: Ay, madam, with the
swiftest wing of speed.")
diff --git a/test/lisp/erc/erc-scenarios-resources/join/network-id/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/join/network-id/foonet.eld
similarity index 95%
rename from test/lisp/erc/erc-scenarios-resources/join/network-id/foonet.eld
rename to test/lisp/erc/erc-scenarios/resources/join/network-id/foonet.eld
index 1162cc3f24..eb44e58a59 100644
--- a/test/lisp/erc/erc-scenarios-resources/join/network-id/foonet.eld
+++ b/test/lisp/erc/erc-scenarios/resources/join/network-id/foonet.eld
@@ -18,22 +18,22 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 1.2 "MODE tester +i"))
+((mode-user 10.2 "MODE tester +i"))
;; No mode answer ^
-((join 1 "JOIN #chan")
+((join 3 "JOIN #chan")
(0 ":tester!~u@q6ddatxcq6txy.irc JOIN #chan")
(0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
(0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
(0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :tester, welcome!")
(0 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :tester, welcome!"))
-((mode 1 "MODE #chan")
+((mode 3 "MODE #chan")
(0 ":irc.foonet.org 324 tester #chan +nt")
(0 ":irc.foonet.org 329 tester #chan 1620608304")
(0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: Pray you, sir, deliver
me this paper.")
(0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: Wake when some vile
thing is near."))
-((quit 1 "QUIT :\2ERC\2"))
+((quit 3 "QUIT :\2ERC\2"))
((drop 0 DROP))
diff --git
a/test/lisp/erc/erc-scenarios-resources/join/reconnect/foonet-again.eld
b/test/lisp/erc/erc-scenarios/resources/join/reconnect/foonet-again.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/join/reconnect/foonet-again.eld
rename to test/lisp/erc/erc-scenarios/resources/join/reconnect/foonet-again.eld
diff --git a/test/lisp/erc/erc-scenarios-resources/join/reconnect/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/join/reconnect/foonet.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/join/reconnect/foonet.eld
rename to test/lisp/erc/erc-scenarios/resources/join/reconnect/foonet.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/networks/announced-missing/foonet.eld
b/test/lisp/erc/erc-scenarios/resources/networks/announced-missing/foonet.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/networks/announced-missing/foonet.eld
rename to
test/lisp/erc/erc-scenarios/resources/networks/announced-missing/foonet.eld
diff --git
a/test/lisp/erc/erc-scenarios-resources/services/auth-source/libera.eld
b/test/lisp/erc/erc-scenarios/resources/services/auth-source/libera.eld
similarity index 100%
rename from
test/lisp/erc/erc-scenarios-resources/services/auth-source/libera.eld
rename to test/lisp/erc/erc-scenarios/resources/services/auth-source/libera.eld
diff --git a/test/lisp/erc/erc-scenarios-resources/services/password/libera.eld
b/test/lisp/erc/erc-scenarios/resources/services/password/libera.eld
similarity index 100%
rename from test/lisp/erc/erc-scenarios-resources/services/password/libera.eld
rename to test/lisp/erc/erc-scenarios/resources/services/password/libera.eld
diff --git a/test/lisp/erc/erc-services-tests.el
b/test/lisp/erc/erc-services-tests.el
index f954d4a77e..947b343278 100644
--- a/test/lisp/erc/erc-services-tests.el
+++ b/test/lisp/erc/erc-services-tests.el
@@ -19,108 +19,181 @@
;;; Commentary:
-;; For convenience, some tests involving core auth-source
-;; functionality have been stashed here for the time being.
+;; TODO: move the auth-source tests somewhere else. They've been
+;; stashed here for pragmatic reasons.
;;; Code:
(require 'ert-x)
(require 'erc-services)
(require 'erc-compat)
+(require 'secrets)
;;;; Core auth-source
+(ert-deftest erc-auth-source-determine-params-merge ()
+ (let ((erc-session-server "irc.gnu.org")
+ (erc-server-announced-name "my.gnu.org")
+ (erc-session-port 6697)
+ (erc-network 'fake)
+ (erc-server-current-nick "tester")
+ (erc-networks--id (erc-networks--id-create 'GNU.chat)))
+
+ (should (equal (erc-auth-source-determine-params-merge)
+ '(:host ("GNU.chat" "my.gnu.org" "irc.gnu.org")
+ :port ("6697" "irc")
+ :require (:secret))))
+
+ (should (equal (erc-auth-source-determine-params-merge :host "fake")
+ '(:host ("fake" "GNU.chat" "my.gnu.org" "irc.gnu.org")
+ :port ("6697" "irc")
+ :require (:secret))))
+
+ (should (equal (erc-auth-source-determine-params-merge
+ :host '("fake") :require :host)
+ '(:host ("fake" "GNU.chat" "my.gnu.org" "irc.gnu.org")
+ :require (:host :secret)
+ :port ("6697" "irc"))))
+
+ (should (equal (erc-auth-source-determine-params-merge
+ :host '("fake" "GNU.chat") :port "1234" :x "x")
+ '(:host ("fake" "GNU.chat" "my.gnu.org" "irc.gnu.org")
+ :port ("1234" "6697" "irc")
+ :x ("x")
+ :require (:secret))))))
+
;; Some of the following may be related to bug#23438.
-(defvar erc-join-tests--auth-source-entries
+(defun erc-services-tests--auth-source-standard (search)
+ (let ((filter #'erc-auth-source-determine-params-merge))
+
+ (ert-info ("Session wins")
+ (let ((erc-session-server "irc.gnu.org")
+ (erc-server-announced-name "my.gnu.org")
+ (erc-session-port 6697)
+ (erc-network 'fake)
+ (erc-server-current-nick "tester")
+ (erc-networks--id (erc-networks--id-create 'GNU.chat)))
+ (should-not (funcall search))
+ (should (string= (apply search (funcall filter :user "#chan"))
+ "foo"))))
+
+ (ert-info ("Network wins")
+ (let* ((erc-session-server "irc.gnu.org")
+ (erc-server-announced-name "my.gnu.org")
+ (erc-session-port 6697)
+ (erc-network 'GNU.chat)
+ (erc-server-current-nick "tester")
+ (erc-networks--id (erc-networks--id-create nil)))
+ (should (string= (apply search (funcall filter :user "#chan"))
+ "foo"))))
+
+ (ert-info ("Announced wins")
+ (let ((erc-session-server "irc.gnu.org")
+ (erc-server-announced-name "my.gnu.org")
+ (erc-session-port 6697)
+ erc-network
+ (erc-networks--id (erc-networks--id-create nil)))
+ (should (string= (apply search (funcall filter :user "#chan"))
+ "baz"))))))
+
+(defun erc-services-tests--auth-source-announced (search)
+ (let* ((erc--isupport-params (make-hash-table))
+ (erc-server-parameters '(("CHANTYPES" . "&#")))
+ (erc--target (erc--target-from-string "&chan"))
+ (filter #'erc-auth-source-determine-params-merge))
+
+ (ert-info ("Announced prioritized")
+
+ (ert-info ("Announced wins")
+ (let* ((erc-session-server "irc.gnu.org")
+ (erc-server-announced-name "my.gnu.org")
+ (erc-session-port 6697)
+ (erc-network 'GNU.chat)
+ (erc-server-current-nick "tester")
+ (erc-networks--id (erc-networks--id-create nil)))
+ (should (string= (apply search (funcall filter :user "#chan"))
+ "baz"))))
+
+ (ert-info ("Peer next")
+ (let* ((erc-server-announced-name "irc.gnu.org")
+ (erc-session-port 6697)
+ (erc-network 'GNU.chat)
+ (erc-server-current-nick "tester")
+ (erc-networks--id (erc-networks--id-create nil)))
+ (should (string= (apply search (funcall filter :user "#chan"))
+ "bar"))))
+
+ (ert-info ("Network used as fallback")
+ (let* ((erc-session-port 6697)
+ (erc-network 'GNU.chat)
+ (erc-server-current-nick "tester")
+ (erc-networks--id (erc-networks--id-create nil)))
+ (should (string= (apply search (funcall filter :user "#chan"))
+ "foo")))))))
+
+(defun erc-services-tests--auth-source-overrides (search)
+ (let* ((erc-session-server "irc.gnu.org")
+ (erc-server-announced-name "my.gnu.org")
+ (erc-network 'GNU.chat)
+ (erc-server-current-nick "tester")
+ (erc-networks--id (erc-networks--id-create nil))
+ (erc-session-port 6667)
+ (filter #'erc-auth-source-determine-params-merge))
+
+ (ert-info ("Specificity and overrides")
+
+ (ert-info ("More specific port")
+ (let ((erc-session-port 6697))
+ (should (string= (apply search (funcall filter :user "#chan"))
+ "spam"))))
+
+ (ert-info ("More specific user (network loses)")
+ (should (string= (apply search (funcall filter :user '("#fsf")))
+ "42")))
+
+ (ert-info ("Actual override")
+ (should (string= (apply search (funcall filter :port "6667"))
+ "sesame")))
+
+ (ert-info ("Overrides don't interfere with post-processing")
+ (should (string= (apply search (funcall filter :host "MyHost"))
+ "123"))))))
+
+;; auth-source netrc backend
+
+(defvar erc-services-tests--auth-source-entries
'("machine irc.gnu.org port irc user \"#chan\" password bar"
"machine my.gnu.org port irc user \"#chan\" password baz"
"machine GNU.chat port irc user \"#chan\" password foo"))
(defun erc-services-tests--auth-source-shuffle (&rest extra)
- (string-join `(,@(sort (append erc-join-tests--auth-source-entries extra)
+ (string-join `(,@(sort (append erc-services-tests--auth-source-entries extra)
(lambda (&rest _) (zerop (random 2))))
"")
"\n"))
-(ert-deftest erc--auth-source-search--standard ()
+(ert-deftest erc--auth-source-search--netrc-standard ()
(ert-with-temp-file netrc-file
:prefix "erc--auth-source-search--standard"
:text (erc-services-tests--auth-source-shuffle)
+
(let ((auth-sources (list netrc-file))
(auth-source-do-cache nil))
+ (erc-services-tests--auth-source-standard
+ #'erc--auth-source-search))))
- (ert-info ("Normal ordering")
-
- (ert-info ("Session wins")
- (let ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- (erc-network 'fake)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create 'GNU.chat)))
- (should (string= (erc--auth-source-search :user "#chan")
- "foo"))))
-
- (ert-info ("Network wins")
- (let* ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "foo"))))
-
- (ert-info ("Announced wins")
- (let ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- erc-network
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "baz"))))))))
-
-(ert-deftest erc--auth-source-search--announced ()
+(ert-deftest erc--auth-source-search--netrc-announced ()
(ert-with-temp-file netrc-file
:prefix "erc--auth-source-search--announced"
:text (erc-services-tests--auth-source-shuffle)
- (let* ((auth-sources (list netrc-file))
- (auth-source-do-cache nil)
- (erc--isupport-params (make-hash-table))
- (erc-server-parameters '(("CHANTYPES" . "&#")))
- (erc--target (erc--target-from-string "&chan")))
-
- (ert-info ("Announced prioritized")
-
- (ert-info ("Announced wins")
- (let* ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "baz"))))
-
- (ert-info ("Peer next")
- (let* ((erc-server-announced-name "irc.gnu.org")
- (erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "bar"))))
-
- (ert-info ("Network used as fallback")
- (let* ((erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "foo"))))))))
-
-(ert-deftest erc--auth-source-search--overrides ()
+
+ (let ((auth-sources (list netrc-file))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-announced
+ #'erc--auth-source-search))))
+
+(ert-deftest erc--auth-source-search--netrc-overrides ()
(ert-with-temp-file netrc-file
:prefix "erc--auth-source-search--overrides"
:text (erc-services-tests--auth-source-shuffle
@@ -130,33 +203,273 @@
"machine MyHost port irc password 456"
"machine MyHost port 6667 password 123")
- (let* ((auth-sources (list netrc-file))
- (auth-source-do-cache nil)
- (erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil))
- (erc-session-port 6667))
-
- (ert-info ("Specificity and overrides")
-
- (ert-info ("More specific port")
- (let ((erc-session-port 6697))
- (should (string= (erc--auth-source-search :user "#chan")
- "spam"))))
-
- (ert-info ("More specific user (network loses)")
- (should (string= (erc--auth-source-search :user '("#fsf"))
- "42")))
+ (let ((auth-sources (list netrc-file))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-overrides
+ #'erc--auth-source-search))))
+
+;; auth-source plstore backend
+
+(defun erc-services-test--call-with-plstore (&rest args)
+ (advice-add 'epg-decrypt-string :override
+ (lambda (&rest r) (prin1-to-string (cadr r)))
+ '((name . erc--auth-source-plstore)))
+ (advice-add 'epg-find-configuration :override
+ (lambda (&rest _) "" '((program . "/bin/true")))
+ '((name . erc--auth-source-plstore)))
+ (unwind-protect
+ (apply #'erc--auth-source-search args)
+ (advice-remove 'epg-decrypt-string 'erc--auth-source-plstore)
+ (advice-remove 'epg-find-configuration 'erc--auth-source-plstore)))
+
+(defvar erc-services-tests--auth-source-plstore-standard-entries
+ '(("ba950d38118a76d71f9f0591bb373d6cb366a512"
+ :secret-secret t
+ :host "irc.gnu.org"
+ :user "#chan"
+ :port "irc")
+ ("7f17ca445d11158065e911a6d0f4cbf52ca250e3"
+ :secret-secret t
+ :host "my.gnu.org"
+ :user "#chan"
+ :port "irc")
+ ("fcd3c8bd6daf4509de0ad6ee98e744ce0fca9377"
+ :secret-secret t
+ :host "GNU.chat"
+ :user "#chan"
+ :port "irc")))
+
+(defvar erc-services-tests--auth-source-plstore-standard-secrets
+ '(("ba950d38118a76d71f9f0591bb373d6cb366a512" :secret "bar")
+ ("7f17ca445d11158065e911a6d0f4cbf52ca250e3" :secret "baz")
+ ("fcd3c8bd6daf4509de0ad6ee98e744ce0fca9377" :secret "foo")))
+
+(ert-deftest erc--auth-source-search--plstore-standard ()
+ (ert-with-temp-file plstore-file
+ :suffix ".plist"
+ :text (concat ";;; public entries -*- mode: plstore -*- \n"
+ (prin1-to-string
+ erc-services-tests--auth-source-plstore-standard-entries)
+ "\n;;; secret entries\n"
+ (prin1-to-string
+ erc-services-tests--auth-source-plstore-standard-secrets)
+ "\n")
+
+ (let ((auth-sources (list plstore-file))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-standard
+ #'erc-services-test--call-with-plstore))))
+
+(ert-deftest erc--auth-source-search--plstore-announced ()
+ (ert-with-temp-file plstore-file
+ :suffix ".plist"
+ :text (concat ";;; public entries -*- mode: plstore -*- \n"
+ (prin1-to-string
+ erc-services-tests--auth-source-plstore-standard-entries)
+ "\n;;; secret entries\n"
+ (prin1-to-string
+ erc-services-tests--auth-source-plstore-standard-secrets)
+ "\n")
+
+ (let ((auth-sources (list plstore-file))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-announced
+ #'erc-services-test--call-with-plstore))))
+
+(ert-deftest erc--auth-source-search--plstore-overrides ()
+ (ert-with-temp-file plstore-file
+ :suffix ".plist"
+ :text (concat
+ ";;; public entries -*- mode: plstore -*- \n"
+ (prin1-to-string
+ `(,@erc-services-tests--auth-source-plstore-standard-entries
+ ("1b3fab249a8dff77a4d8fe7eb4b0171b25cc711a"
+ :secret-secret t :host "GNU.chat" :user "#chan" :port "6697")
+ ("6cbcdc39476b8cfcca6f3e9a7876f41ec3f708cc"
+ :secret-secret t :host "my.gnu.org" :user "#fsf" :port "irc")
+ ("a33e2b3bd2d6f33995a4b88710a594a100c5e41d"
+ :secret-secret t :host "irc.gnu.org" :port "6667")
+ ("ab2fd349b2b7d6a9215bb35a92d054261b0b1537"
+ :secret-secret t :host "MyHost" :port "irc")
+ ("61a6bd552059494f479ff720e8de33e22574650a"
+ :secret-secret t :host "MyHost" :port "6667")))
+ "\n;;; secret entries\n"
+ (prin1-to-string
+ `(,@erc-services-tests--auth-source-plstore-standard-secrets
+ ("1b3fab249a8dff77a4d8fe7eb4b0171b25cc711a" :secret "spam")
+ ("6cbcdc39476b8cfcca6f3e9a7876f41ec3f708cc" :secret "42")
+ ("a33e2b3bd2d6f33995a4b88710a594a100c5e41d" :secret "sesame")
+ ("ab2fd349b2b7d6a9215bb35a92d054261b0b1537" :secret "456")
+ ("61a6bd552059494f479ff720e8de33e22574650a" :secret "123")))
+ "\n")
+
+ (let ((auth-sources (list plstore-file))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-overrides
+ #'erc-services-test--call-with-plstore))))
+
+;; auth-source JSON backend
+
+(defvar erc-services-tests--auth-source-json-standard-entries
+ [(:host "irc.gnu.org" :port "irc" :user "#chan" :secret "bar")
+ (:host "my.gnu.org" :port "irc" :user "#chan" :secret "baz")
+ (:host "GNU.chat" :port "irc" :user "#chan" :secret "foo")])
+
+(ert-deftest erc--auth-source-search--json-standard ()
+ (ert-with-temp-file json-store
+ :suffix ".json"
+ :text (let ((json-object-type 'plist))
+ (json-encode
+ erc-services-tests--auth-source-json-standard-entries))
+ (let ((auth-sources (list json-store))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-standard
+ #'erc--auth-source-search))))
- (ert-info ("Actual override")
- (should (string= (erc--auth-source-search :port "6667")
- "sesame")))
+(ert-deftest erc--auth-source-search--json-announced ()
+ (ert-with-temp-file plstore-file
+ :suffix ".json"
+ :text (let ((json-object-type 'plist))
+ (json-encode
+ erc-services-tests--auth-source-json-standard-entries))
- (ert-info ("Overrides don't interfere with post-processing")
- (should (string= (erc--auth-source-search :host "MyHost")
- "123")))))))
+ (let ((auth-sources (list plstore-file))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-announced
+ #'erc--auth-source-search))))
+
+(ert-deftest erc--auth-source-search--json-overrides ()
+ (ert-with-temp-file json-file
+ :suffix ".json"
+ :text (let ((json-object-type 'plist))
+ (json-encode
+ (vconcat
+ erc-services-tests--auth-source-json-standard-entries
+ [(:secret "spam" :host "GNU.chat" :user "#chan" :port "6697")
+ (:secret "42" :host "my.gnu.org" :user "#fsf" :port "irc")
+ (:secret "sesame" :host "irc.gnu.org" :port "6667")
+ (:secret "456" :host "MyHost" :port "irc")
+ (:secret "123" :host "MyHost" :port "6667")])))
+
+ (let ((auth-sources (list json-file))
+ (auth-source-do-cache nil))
+ (erc-services-tests--auth-source-overrides
+ #'erc--auth-source-search))))
+
+;; auth-source-secrets backend
+
+(defvar erc-services-tests--auth-source-secrets-standard-entries
+ '(("#chan@irc.gnu.org:irc" ; label
+ (:host . "irc.gnu.org")
+ (:user . "#chan")
+ (:port . "irc")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))
+ ("#chan@my.gnu.org:irc"
+ (:host . "my.gnu.org")
+ (:user . "#chan")
+ (:port . "irc")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))
+ ("#chan@GNU.chat:irc"
+ (:host . "GNU.chat")
+ (:user . "#chan")
+ (:port . "irc")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))))
+
+(defvar erc-services-tests--auth-source-secrets-standard-secrets
+ '(("#chan@irc.gnu.org:irc" . "bar")
+ ("#chan@my.gnu.org:irc" . "baz")
+ ("#chan@GNU.chat:irc" . "foo")))
+
+(ert-deftest erc--auth-source-search--secrets-standard ()
+ (skip-unless (bound-and-true-p secrets-enabled))
+ (let ((auth-sources '("secrets:Test"))
+ (auth-source-do-cache nil)
+ (entries erc-services-tests--auth-source-secrets-standard-entries)
+ (secrets erc-services-tests--auth-source-secrets-standard-secrets))
+
+ (cl-letf (((symbol-function 'secrets-search-items)
+ (lambda (col &rest r)
+ (should (equal col "Test"))
+ (should (plist-get r :user))
+ (map-keys entries)))
+ ((symbol-function 'secrets-get-secret)
+ (lambda (col label)
+ (should (equal col "Test"))
+ (assoc-default label secrets)))
+ ((symbol-function 'secrets-get-attributes)
+ (lambda (col label)
+ (should (equal col "Test"))
+ (assoc-default label entries))))
+
+ (erc-services-tests--auth-source-standard
+ #'erc--auth-source-search))))
+
+(ert-deftest erc--auth-source-search--secrets-announced ()
+ (skip-unless (bound-and-true-p secrets-enabled))
+ (let ((auth-sources '("secrets:Test"))
+ (auth-source-do-cache nil)
+ (entries erc-services-tests--auth-source-secrets-standard-entries)
+ (secrets erc-services-tests--auth-source-secrets-standard-secrets))
+
+ (cl-letf (((symbol-function 'secrets-search-items)
+ (lambda (col &rest r)
+ (should (equal col "Test"))
+ (should (plist-get r :user))
+ (map-keys entries)))
+ ((symbol-function 'secrets-get-secret)
+ (lambda (col label)
+ (should (equal col "Test"))
+ (assoc-default label secrets)))
+ ((symbol-function 'secrets-get-attributes)
+ (lambda (col label)
+ (should (equal col "Test"))
+ (assoc-default label entries))))
+
+ (erc-services-tests--auth-source-announced
+ #'erc--auth-source-search))))
+
+(ert-deftest erc--auth-source-search--secrets-overrides ()
+ (skip-unless (bound-and-true-p secrets-enabled))
+ (let ((auth-sources '("secrets:Test"))
+ (auth-source-do-cache nil)
+ (entries `(,@erc-services-tests--auth-source-secrets-standard-entries
+ ("#chan@GNU.chat:6697"
+ (:host . "GNU.chat") (:user . "#chan") (:port . "6697")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))
+ ("#fsf@my.gnu.org:irc"
+ (:host . "my.gnu.org") (:user . "#fsf") (:port . "irc")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))
+ ("irc.gnu.org:6667"
+ (:host . "irc.gnu.org") (:port . "6667")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))
+ ("MyHost:irc"
+ (:host . "MyHost") (:port . "irc")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))
+ ("MyHost:6667"
+ (:host . "MyHost") (:port . "6667")
+ (:xdg:schema . "org.freedesktop.Secret.Generic"))))
+ (secrets `(,@erc-services-tests--auth-source-secrets-standard-secrets
+ ("#chan@GNU.chat:6697" . "spam")
+ ("#fsf@my.gnu.org:irc" . "42" )
+ ("irc.gnu.org:6667" . "sesame")
+ ("MyHost:irc" . "456")
+ ("MyHost:6667" . "123"))))
+
+ (cl-letf (((symbol-function 'secrets-search-items)
+ (lambda (col &rest _)
+ (should (equal col "Test"))
+ (map-keys entries)))
+ ((symbol-function 'secrets-get-secret)
+ (lambda (col label)
+ (should (equal col "Test"))
+ (assoc-default label secrets)))
+ ((symbol-function 'secrets-get-attributes)
+ (lambda (col label)
+ (should (equal col "Test"))
+ (assoc-default label entries))))
+
+ (erc-services-tests--auth-source-overrides
+ #'erc--auth-source-search))))
;; auth-source-pass backend
@@ -185,7 +498,8 @@
("GNU.chat:irc/#chan"
("port" . "irc") ("user" . "#chan") (secret . "foo"))))
-(ert-deftest erc-services-tests--auth-source-pass--standard ()
+(ert-deftest erc--auth-source-search--pass-standard ()
+ (ert-skip "Pass backend not yet supported")
(let ((store erc-join-tests--auth-source-pass-entries)
(auth-sources '(password-store))
(auth-source-do-cache nil))
@@ -195,38 +509,10 @@
((symbol-function 'auth-source-pass-entries)
(lambda () (mapcar #'car store))))
- (ert-info ("Normal ordering")
-
- (ert-info ("Session wins")
- (let ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- (erc-network 'fake)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create 'GNU.chat)))
- (should (string= (erc--auth-source-search :user "#chan")
- "foo"))))
-
- (ert-info ("Network wins")
- (let* ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "foo"))))
-
- (ert-info ("Announced wins")
- (let ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- erc-network
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "baz"))))))))
-
-(ert-deftest erc-services-tests--auth-source-pass--announced ()
+ (erc-services-tests--auth-source-standard #'erc--auth-source-search))))
+
+(ert-deftest erc--auth-source-search--pass-announced ()
+ (ert-skip "Pass backend not yet supported")
(let ((store erc-join-tests--auth-source-pass-entries)
(auth-sources '(password-store))
(auth-source-do-cache nil))
@@ -236,79 +522,31 @@
((symbol-function 'auth-source-pass-entries)
(lambda () (mapcar #'car store))))
- (let* ((erc--isupport-params (make-hash-table))
- (erc-server-parameters '(("CHANTYPES" . "&#")))
- (erc--target (erc--target-from-string "&chan")))
-
- (ert-info ("Announced prioritized")
-
- (ert-info ("Announced wins")
- (let* ((erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "baz"))))
-
- (ert-info ("Peer next")
- (let* ((erc-server-announced-name "irc.gnu.org")
- (erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "bar"))))
-
- (ert-info ("Network used as fallback")
- (let* ((erc-session-port 6697)
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil)))
- (should (string= (erc--auth-source-search :user "#chan")
- "foo")))))))))
-
-(ert-deftest erc-services-tests--auth-source-pass--overrides ()
- (let* ((store
- `(,@erc-join-tests--auth-source-pass-entries
- ("GNU.chat:6697/#chan"
- ("port" . "6697") ("user" . "#chan") (secret . "spam"))
- ("my.gnu.org:irc/#fsf"
- ("port" . "irc") ("user" . "#fsf") (secret . "42"))
- ("irc.gnu.org:6667"
- ("port" . "6667") (secret . "sesame"))
- ("MyHost:irc"
- ("port" . "irc") (secret . "456"))
- ("MyHost:6667"
- ("port" . "6667") (secret . "123"))))
- (auth-sources '(password-store))
- (auth-source-do-cache nil)
- (erc-session-server "irc.gnu.org")
- (erc-server-announced-name "my.gnu.org")
- (erc-network 'GNU.chat)
- (erc-server-current-nick "tester")
- (erc-networks--id (erc-networks--id-create nil))
- (erc-session-port 6667))
+ (erc-services-tests--auth-source-announced #'erc--auth-source-search))))
+
+(ert-deftest erc--auth-source-search--pass-overrides ()
+ (ert-skip "Pass backend not yet supported")
+ (let ((store
+ `(,@erc-join-tests--auth-source-pass-entries
+ ("GNU.chat:6697/#chan"
+ ("port" . "6697") ("user" . "#chan") (secret . "spam"))
+ ("my.gnu.org:irc/#fsf"
+ ("port" . "irc") ("user" . "#fsf") (secret . "42"))
+ ("irc.gnu.org:6667"
+ ("port" . "6667") (secret . "sesame"))
+ ("MyHost:irc"
+ ("port" . "irc") (secret . "456"))
+ ("MyHost:6667"
+ ("port" . "6667") (secret . "123"))))
+ (auth-sources '(password-store))
+ (auth-source-do-cache nil))
(cl-letf (((symbol-function 'auth-source-pass-parse-entry)
(apply-partially #'erc-services-tests--asp-parse-entry store))
((symbol-function 'auth-source-pass-entries)
(lambda () (mapcar #'car store))))
- (ert-info ("More specific port")
- (let ((erc-session-port 6697))
- (should (string= (erc--auth-source-search :user "#chan") "spam"))))
-
- (ert-info ("Network wins")
- (should (string= (erc--auth-source-search :user '("#fsf")) "42")))
-
- (ert-info ("Actual override")
- (should (string= (erc--auth-source-search :port "6667") "sesame")))
-
- (ert-info ("Overrides don't interfere with post-processing")
- (should (string= (erc--auth-source-search :host "MyHost")
- "123"))))))
+ (erc-services-tests--auth-source-overrides #'erc--auth-source-search))))
;;;; The services module
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 0392005a43..be09207b0d 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -169,6 +169,14 @@
(get-buffer "ServNet"))
erc-default-recipients '("#chan")))
+ (with-current-buffer (get-buffer-create "bob")
+ (erc-tests--send-prep)
+ (goto-char erc-insert-marker)
+ (should (looking-at-p (regexp-quote erc-prompt)))
+ (setq erc-server-process (buffer-local-value 'erc-server-process
+ (get-buffer "ServNet"))
+ erc-default-recipients '("bob")))
+
(ert-info ("Value: t (default)")
(should (eq erc-hide-prompt t))
(with-current-buffer "ServNet"
@@ -187,6 +195,17 @@
(should-not (memq #'erc--unhide-prompt-on-self-insert
pre-command-hook)))
+ (with-current-buffer "bob"
+ (goto-char erc-insert-marker)
+ (should (string= ">" (get-text-property (point) 'display)))
+ (should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
+ (goto-char erc-input-marker)
+ (ert-simulate-command '(self-insert-command 1 ?/))
+ (goto-char erc-insert-marker)
+ (should-not (get-text-property (point) 'display))
+ (should-not (memq #'erc--unhide-prompt-on-self-insert
+ pre-command-hook)))
+
(with-current-buffer "ServNet"
(should (get-text-property erc-insert-marker 'display))
(should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
@@ -196,7 +215,7 @@
(should-not (get-text-property erc-insert-marker 'display))))
(ert-info ("Value: server")
- (setq erc-hide-prompt 'server)
+ (setq erc-hide-prompt '(server))
(with-current-buffer "ServNet"
(erc--hide-prompt erc-server-process)
(should (string= ">" (get-text-property erc-insert-marker 'display))))
@@ -204,27 +223,50 @@
(with-current-buffer "#chan"
(should-not (get-text-property erc-insert-marker 'display)))
+ (with-current-buffer "bob"
+ (should-not (get-text-property erc-insert-marker 'display)))
+
(with-current-buffer "ServNet"
(erc--unhide-prompt)
(should-not (get-text-property erc-insert-marker 'display))))
- (ert-info ("Value: target")
- (setq erc-hide-prompt 'target)
+ (ert-info ("Value: channel")
+ (setq erc-hide-prompt '(channel))
(with-current-buffer "ServNet"
(erc--hide-prompt erc-server-process)
(should-not (get-text-property erc-insert-marker 'display)))
+ (with-current-buffer "bob"
+ (should-not (get-text-property erc-insert-marker 'display)))
+
(with-current-buffer "#chan"
(should (string= ">" (get-text-property erc-insert-marker 'display)))
(erc--unhide-prompt)
(should-not (get-text-property erc-insert-marker 'display))))
+ (ert-info ("Value: query")
+ (setq erc-hide-prompt '(query))
+ (with-current-buffer "ServNet"
+ (erc--hide-prompt erc-server-process)
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "bob"
+ (should (string= ">" (get-text-property erc-insert-marker 'display)))
+ (erc--unhide-prompt)
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "#chan"
+ (should-not (get-text-property erc-insert-marker 'display))))
+
(ert-info ("Value: nil")
(setq erc-hide-prompt nil)
(with-current-buffer "ServNet"
(erc--hide-prompt erc-server-process)
(should-not (get-text-property erc-insert-marker 'display)))
+ (with-current-buffer "bob"
+ (should-not (get-text-property erc-insert-marker 'display)))
+
(with-current-buffer "#chan"
(should-not (get-text-property erc-insert-marker 'display))
(erc--unhide-prompt) ; won't blow up when prompt already showing
@@ -232,6 +274,7 @@
(when noninteractive
(kill-buffer "#chan")
+ (kill-buffer "bob")
(kill-buffer "ServNet"))))
(ert-deftest erc--switch-to-buffer ()
@@ -423,17 +466,17 @@
(should (equal (erc-downcase "Tilde~") "tilde~" ))
(should (equal (erc-downcase "\\O/") "|o/" )))))
-(ert-deftest erc-local-channel-p ()
+(ert-deftest erc--valid-local-channel-p ()
(ert-info ("Local channels not supported")
(let ((erc--isupport-params (make-hash-table)))
(puthash 'CHANTYPES '("#") erc--isupport-params)
- (should-not (erc-valid-local-channel-p "#chan"))
- (should-not (erc-valid-local-channel-p "&local"))))
+ (should-not (erc--valid-local-channel-p "#chan"))
+ (should-not (erc--valid-local-channel-p "&local"))))
(ert-info ("Local channels supported")
(let ((erc--isupport-params (make-hash-table)))
(puthash 'CHANTYPES '("&#") erc--isupport-params)
- (should-not (erc-valid-local-channel-p "#chan"))
- (should (erc-valid-local-channel-p "&local")))))
+ (should-not (erc--valid-local-channel-p "#chan"))
+ (should (erc--valid-local-channel-p "&local")))))
(ert-deftest erc--target-from-string ()
(should (equal (erc--target-from-string "#chan")