aboutsummaryrefslogtreecommitdiff
path: root/tests/test-signal-config.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-signal-config.el')
-rw-r--r--tests/test-signal-config.el141
1 files changed, 141 insertions, 0 deletions
diff --git a/tests/test-signal-config.el b/tests/test-signal-config.el
new file mode 100644
index 00000000..40879342
--- /dev/null
+++ b/tests/test-signal-config.el
@@ -0,0 +1,141 @@
+;;; test-signal-config.el --- Tests for signal-config -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; ERT tests for the pure helper layer of `signal-config': contact-list
+;; parsing for the contact picker, and the notify-when-not-viewing
+;; predicate. These need neither signal-cli nor a linked account.
+
+;;; Code:
+
+(require 'ert)
+(require 'json)
+(require 'signal-config)
+
+;;; cj/signal--jstr
+
+(ert-deftest test-signal-config-jstr-string ()
+ "Normal: a non-blank string passes through unchanged."
+ (should (equal (cj/signal--jstr "hi") "hi")))
+
+(ert-deftest test-signal-config-jstr-rejects-nonstrings ()
+ "Boundary/Error: nil, empty, whitespace, and non-string sentinels become nil."
+ (should-not (cj/signal--jstr nil))
+ (should-not (cj/signal--jstr ""))
+ (should-not (cj/signal--jstr " "))
+ (should-not (cj/signal--jstr :null))
+ (should-not (cj/signal--jstr 42)))
+
+;;; cj/signal--contact-display-name
+;; Field priority: nickName, then nickGiven+nickFamily, then top-level name,
+;; then top-level given+family, then profile given+family, then username.
+
+(ert-deftest test-signal-config-display-name-prefers-name ()
+ "Normal: the top-level combined name wins over the given/family parts."
+ (should (equal (cj/signal--contact-display-name
+ '((name . "Alice Anderson") (givenName . "Ali") (familyName . "A")))
+ "Alice Anderson")))
+
+(ert-deftest test-signal-config-display-name-nickname-wins ()
+ "Normal: a nickName overrides the contact name."
+ (should (equal (cj/signal--contact-display-name
+ '((nickName . "Edster") (name . "Eve Edwards")
+ (givenName . "Eve") (familyName . "Edwards")))
+ "Edster")))
+
+(ert-deftest test-signal-config-display-name-nickname-parts ()
+ "Boundary: nickGivenName+nickFamilyName combine when nickName is unset."
+ (should (equal (cj/signal--contact-display-name
+ '((nickGivenName . "DJ") (nickFamilyName . "Cool") (name . "Daniel")))
+ "DJ Cool")))
+
+(ert-deftest test-signal-config-display-name-toplevel-given-family ()
+ "Boundary: with no name, top-level givenName+familyName combine."
+ (should (equal (cj/signal--contact-display-name
+ '((name) (givenName . "Bob") (familyName . "Brown")))
+ "Bob Brown")))
+
+(ert-deftest test-signal-config-display-name-profile-fallback ()
+ "Boundary: with no name or top-level parts, profile given/family is the fallback."
+ (should (equal (cj/signal--contact-display-name
+ '((name) (givenName) (familyName)
+ (profile . ((givenName . "Carol") (familyName)))))
+ "Carol")))
+
+(ert-deftest test-signal-config-display-name-username-fallback ()
+ "Boundary: username is the last name source."
+ (should (equal (cj/signal--contact-display-name
+ '((name) (username . "dave.42")))
+ "dave.42")))
+
+(ert-deftest test-signal-config-display-name-none ()
+ "Error: no usable name yields nil."
+ (should-not (cj/signal--contact-display-name
+ '((name) (givenName) (familyName)
+ (profile . ((givenName) (familyName))))))
+ (should-not (cj/signal--contact-display-name '((number . "+15551112222")))))
+
+;;; cj/signal--parse-contacts
+
+(defconst test-signal-config--contacts-json
+ "[
+ {\"number\":\"+15551112222\",\"uuid\":\"uuid-a\",\"name\":\"Alice Anderson\",\"givenName\":\"Alice\",\"familyName\":\"Anderson\",\"nickName\":null,\"nickGivenName\":null,\"nickFamilyName\":null,\"username\":null,\"profile\":{\"givenName\":null,\"familyName\":null}},
+ {\"number\":\"+15553334444\",\"uuid\":null,\"name\":null,\"givenName\":\"Bob\",\"familyName\":\"Brown\",\"nickName\":null,\"username\":null,\"profile\":{\"givenName\":null,\"familyName\":null}},
+ {\"number\":\"+15555556666\",\"uuid\":\"uuid-c\",\"name\":null,\"givenName\":null,\"familyName\":null,\"nickName\":null,\"username\":null,\"profile\":{\"givenName\":\"Carol\",\"familyName\":null}},
+ {\"number\":null,\"uuid\":\"uuid-d\",\"name\":null,\"givenName\":null,\"familyName\":null,\"username\":null,\"profile\":{\"givenName\":null,\"familyName\":null}},
+ {\"number\":\"+15557778888\",\"uuid\":\"uuid-e\",\"name\":\"Eve Edwards\",\"givenName\":\"Eve\",\"familyName\":\"Edwards\",\"nickName\":\"Edster\",\"username\":null,\"profile\":{\"givenName\":null,\"familyName\":null}}
+]"
+ "Synthetic fixture mirroring the signal-cli 0.14.4.1 `listContacts' shape:
+top-level name/givenName/familyName and nickName fields, with a profile
+sub-object whose name fields are usually null. Field layout was confirmed
+against a live linked account on 2026-05-26; the values here are fake.")
+
+(ert-deftest test-signal-config-parse-contacts-normal ()
+ "Normal: top-level name, top-level parts, profile fallback, uuid fallback, nickname."
+ (let* ((result (json-read-from-string test-signal-config--contacts-json))
+ (pairs (cj/signal--parse-contacts result)))
+ (should (equal pairs
+ '(("Alice Anderson (+15551112222)" . "+15551112222")
+ ("Bob Brown (+15553334444)" . "+15553334444")
+ ("Carol (+15555556666)" . "+15555556666")
+ ("Edster (+15557778888)" . "+15557778888")
+ ("uuid-d" . "uuid-d"))))))
+
+(ert-deftest test-signal-config-parse-contacts-empty ()
+ "Boundary: an empty result yields nil for both vector and nil input."
+ (should-not (cj/signal--parse-contacts []))
+ (should-not (cj/signal--parse-contacts nil)))
+
+(ert-deftest test-signal-config-parse-contacts-accepts-list-and-vector ()
+ "Boundary: vector and list result sequences parse identically."
+ (let ((entry '((number . "+15551112222") (name . "Al"))))
+ (should (equal (cj/signal--parse-contacts (vector entry))
+ (cj/signal--parse-contacts (list entry))))))
+
+(ert-deftest test-signal-config-parse-contacts-drops-recipientless ()
+ "Error: a contact with neither number nor uuid is dropped."
+ (should-not (cj/signal--parse-contacts
+ (list '((name . "Ghost") (number) (uuid))))))
+
+;;; cj/signal--suppress-notify-p
+
+(ert-deftest test-signal-config-suppress-when-viewing-focused ()
+ "Normal: viewing the chat buffer with focus suppresses the notification."
+ (should (cj/signal--suppress-notify-p
+ "+15551112222" "*Signel: +15551112222*" t)))
+
+(ert-deftest test-signal-config-no-suppress-other-buffer ()
+ "Boundary: a different selected buffer does not suppress."
+ (should-not (cj/signal--suppress-notify-p
+ "+15551112222" "*scratch*" t)))
+
+(ert-deftest test-signal-config-no-suppress-unfocused ()
+ "Boundary: viewing the chat but with the frame unfocused still notifies."
+ (should-not (cj/signal--suppress-notify-p
+ "+15551112222" "*Signel: +15551112222*" nil)))
+
+(ert-deftest test-signal-config-no-suppress-nil-viewing ()
+ "Error: a nil viewing-buffer name does not suppress."
+ (should-not (cj/signal--suppress-notify-p "+15551112222" nil t)))
+
+(provide 'test-signal-config)
+;;; test-signal-config.el ends here