diff options
| -rw-r--r-- | tests/test-host-environment--detect-system-timezone.el | 78 | ||||
| -rw-r--r-- | tests/test-host-environment--display-predicates.el | 112 | ||||
| -rw-r--r-- | tests/test-host-environment--env-laptop-p.el | 92 | ||||
| -rw-r--r-- | tests/test-host-environment--platform-predicates.el | 63 |
4 files changed, 345 insertions, 0 deletions
diff --git a/tests/test-host-environment--detect-system-timezone.el b/tests/test-host-environment--detect-system-timezone.el new file mode 100644 index 00000000..c24ac183 --- /dev/null +++ b/tests/test-host-environment--detect-system-timezone.el @@ -0,0 +1,78 @@ +;;; test-host-environment--detect-system-timezone.el --- Tests for cj/detect-system-timezone -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `cj/detect-system-timezone'. The function tries four +;; detection methods in priority order: file-content match against +;; zoneinfo, the TZ env var, /etc/timezone, and the /etc/localtime +;; symlink target. Tests mock the first two methods to verify the +;; priority chain without touching real system files. Methods 3 and +;; 4 (file I/O on /etc) are exercised end-to-end on the real host but +;; not asserted strictly — those would be brittle across machines. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'host-environment) + +(ert-deftest test-host-environment-detect-tz-match-localtime-wins () + "Normal: when match-localtime-to-zoneinfo returns a value, that wins." + (cl-letf (((symbol-function 'cj/match-localtime-to-zoneinfo) + (lambda () "America/Los_Angeles")) + ((symbol-function 'getenv) + (lambda (_) (error "TZ should not have been consulted")))) + (should (equal (cj/detect-system-timezone) "America/Los_Angeles")))) + +(ert-deftest test-host-environment-detect-tz-env-var-wins-when-match-nil () + "Normal: with match-localtime nil, the TZ env var is used." + (cl-letf (((symbol-function 'cj/match-localtime-to-zoneinfo) + (lambda () nil)) + ((symbol-function 'getenv) + (lambda (name) (when (string= name "TZ") "Europe/Berlin")))) + (should (equal (cj/detect-system-timezone) "Europe/Berlin")))) + +(ert-deftest test-host-environment-detect-tz-falls-through-to-etc-timezone () + "Boundary: with match-localtime and TZ both nil, /etc/timezone is read. +Uses a real temp file substituted via cl-letf on the file-existence and +contents primitives." + (let ((fake-tz "Asia/Tokyo")) + (cl-letf (((symbol-function 'cj/match-localtime-to-zoneinfo) + (lambda () nil)) + ((symbol-function 'getenv) + (lambda (_) nil)) + ((symbol-function 'file-exists-p) + (lambda (path) (string= path "/etc/timezone"))) + ((symbol-function 'insert-file-contents) + (lambda (path &rest _) + (when (string= path "/etc/timezone") + (insert fake-tz "\n"))))) + (should (equal (cj/detect-system-timezone) fake-tz))))) + +(ert-deftest test-host-environment-detect-tz-trims-etc-timezone-whitespace () + "Boundary: trailing whitespace in /etc/timezone is trimmed." + (cl-letf (((symbol-function 'cj/match-localtime-to-zoneinfo) + (lambda () nil)) + ((symbol-function 'getenv) + (lambda (_) nil)) + ((symbol-function 'file-exists-p) + (lambda (path) (string= path "/etc/timezone"))) + ((symbol-function 'insert-file-contents) + (lambda (path &rest _) + (when (string= path "/etc/timezone") + (insert " America/Chicago\n\n"))))) + (should (equal (cj/detect-system-timezone) "America/Chicago")))) + +(ert-deftest test-host-environment-detect-tz-returns-nil-when-all-fail () + "Error: returns nil when every detection method fails." + (cl-letf (((symbol-function 'cj/match-localtime-to-zoneinfo) + (lambda () nil)) + ((symbol-function 'getenv) + (lambda (_) nil)) + ((symbol-function 'file-exists-p) (lambda (_) nil)) + ((symbol-function 'file-symlink-p) (lambda (_) nil))) + (should-not (cj/detect-system-timezone)))) + +(provide 'test-host-environment--detect-system-timezone) +;;; test-host-environment--detect-system-timezone.el ends here diff --git a/tests/test-host-environment--display-predicates.el b/tests/test-host-environment--display-predicates.el new file mode 100644 index 00000000..15dff2ef --- /dev/null +++ b/tests/test-host-environment--display-predicates.el @@ -0,0 +1,112 @@ +;;; test-host-environment--display-predicates.el --- Tests for env-x/x11/wayland/terminal/gui-p -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for the display-environment predicates in host-environment.el. +;; Mocks `window-system', `getenv', and `display-graphic-p' at the +;; framework boundary so each predicate can be exercised under every +;; relevant combination of (window-system, WAYLAND_DISPLAY, graphic-p). + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'host-environment) + +(defmacro test-host-env--with-display (window-system-value + wayland-display + graphic-p + &rest body) + "Run BODY with display state stubbed. +WINDOW-SYSTEM-VALUE becomes the return of `(window-system)'. +WAYLAND-DISPLAY becomes the value of $WAYLAND_DISPLAY (nil for unset). +GRAPHIC-P becomes the return of `(display-graphic-p)'." + (declare (indent 3) (debug t)) + `(cl-letf (((symbol-function 'window-system) + (lambda (&optional _) ,window-system-value)) + ((symbol-function 'getenv) + (lambda (name) + (when (string= name "WAYLAND_DISPLAY") ,wayland-display))) + ((symbol-function 'display-graphic-p) + (lambda (&optional _) ,graphic-p))) + ,@body)) + +;;; env-x-p + +(ert-deftest test-host-environment-x-p-true-when-window-system-is-x () + "Normal: env-x-p returns t when window-system is `x'." + (test-host-env--with-display 'x nil t + (should (env-x-p)))) + +(ert-deftest test-host-environment-x-p-false-when-window-system-is-pgtk () + "Boundary: env-x-p returns nil when window-system is `pgtk'." + (test-host-env--with-display 'pgtk nil t + (should-not (env-x-p)))) + +(ert-deftest test-host-environment-x-p-false-when-no-window-system () + "Boundary: env-x-p returns nil under no window system (terminal)." + (test-host-env--with-display nil nil nil + (should-not (env-x-p)))) + +;;; env-x11-p + +(ert-deftest test-host-environment-x11-p-true-on-x-without-wayland-display () + "Normal: env-x11-p returns t under X with no WAYLAND_DISPLAY." + (test-host-env--with-display 'x nil t + (should (env-x11-p)))) + +(ert-deftest test-host-environment-x11-p-false-under-xwayland () + "Boundary: env-x11-p returns nil when running through XWayland. +Detected via WAYLAND_DISPLAY being set even though window-system is `x'." + (test-host-env--with-display 'x "wayland-0" t + (should-not (env-x11-p)))) + +(ert-deftest test-host-environment-x11-p-false-on-pgtk () + "Boundary: env-x11-p returns nil under pure-GTK Wayland." + (test-host-env--with-display 'pgtk "wayland-0" t + (should-not (env-x11-p)))) + +;;; env-wayland-p + +(ert-deftest test-host-environment-wayland-p-true-when-wayland-display-set () + "Normal: env-wayland-p returns t when WAYLAND_DISPLAY is set." + (test-host-env--with-display 'pgtk "wayland-0" t + (should (env-wayland-p)))) + +(ert-deftest test-host-environment-wayland-p-false-when-wayland-display-unset () + "Boundary: env-wayland-p returns nil when WAYLAND_DISPLAY is unset." + (test-host-env--with-display 'x nil t + (should-not (env-wayland-p)))) + +(ert-deftest test-host-environment-wayland-p-true-under-xwayland () + "Boundary: env-wayland-p returns t even under XWayland. +WAYLAND_DISPLAY is set by the compositor regardless of which X surface +Emacs uses, so XWayland counts as Wayland by this predicate." + (test-host-env--with-display 'x "wayland-0" t + (should (env-wayland-p)))) + +;;; env-terminal-p / env-gui-p + +(ert-deftest test-host-environment-terminal-p-true-when-not-graphical () + "Normal: env-terminal-p returns t when display-graphic-p is nil." + (test-host-env--with-display nil nil nil + (should (env-terminal-p)))) + +(ert-deftest test-host-environment-terminal-p-false-when-graphical () + "Boundary: env-terminal-p returns nil under a graphical frame." + (test-host-env--with-display 'x nil t + (should-not (env-terminal-p)))) + +(ert-deftest test-host-environment-gui-p-true-when-graphical () + "Normal: env-gui-p returns t under a graphical frame." + (test-host-env--with-display 'x nil t + (should (env-gui-p)))) + +(ert-deftest test-host-environment-gui-p-false-in-terminal () + "Boundary: env-gui-p returns nil under a terminal frame." + (test-host-env--with-display nil nil nil + (should-not (env-gui-p)))) + +(provide 'test-host-environment--display-predicates) +;;; test-host-environment--display-predicates.el ends here diff --git a/tests/test-host-environment--env-laptop-p.el b/tests/test-host-environment--env-laptop-p.el new file mode 100644 index 00000000..da00954c --- /dev/null +++ b/tests/test-host-environment--env-laptop-p.el @@ -0,0 +1,92 @@ +;;; test-host-environment--env-laptop-p.el --- Tests for env-laptop-p / env-desktop-p -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `env-laptop-p' and the inverse `env-desktop-p'. On Linux, +;; the function delegates to `env--power-supply-has-battery-p' against +;; /sys/class/power_supply. On other platforms, it reads the battery +;; status char. Tests mock `system-type' and the helpers at their +;; boundary so the predicate's dispatch logic is exercised without +;; touching real system files. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'host-environment) + +;; Forward-declare and initialize to nil so let-binding inside tests +;; sees this as special under lexical-binding, and so cl-letf's +;; symbol-value place can read the old value without hitting void-variable. +(defvar battery-status-function nil) + +;;; env-laptop-p — Linux dispatch + +(ert-deftest test-host-environment-laptop-p-linux-with-battery () + "Normal: on Linux, env-laptop-p delegates to power-supply helper." + (let ((system-type 'gnu/linux)) + (cl-letf (((symbol-function 'env--power-supply-has-battery-p) + (lambda (_dir) t))) + (should (env-laptop-p))))) + +(ert-deftest test-host-environment-laptop-p-linux-without-battery () + "Boundary: on Linux, env-laptop-p returns nil when no BAT* dir is found." + (let ((system-type 'gnu/linux)) + (cl-letf (((symbol-function 'env--power-supply-has-battery-p) + (lambda (_dir) nil))) + (should-not (env-laptop-p))))) + +(ert-deftest test-host-environment-laptop-p-linux-passes-correct-dir () + "Boundary: on Linux, the power-supply helper receives /sys/class/power_supply." + (let ((system-type 'gnu/linux) + captured) + (cl-letf (((symbol-function 'env--power-supply-has-battery-p) + (lambda (dir) (setq captured dir) t))) + (env-laptop-p) + (should (equal captured "/sys/class/power_supply"))))) + +;;; env-laptop-p — non-Linux dispatch via battery-format + +(ert-deftest test-host-environment-laptop-p-non-linux-with-battery-char () + "Normal: on non-Linux, env-laptop-p reads the battery status char." + (let ((system-type 'darwin)) + (cl-letf (((symbol-function 'require) + (lambda (feat &rest _) (eq feat 'battery))) + ((symbol-function 'battery-format) + (lambda (_format _data) "+")) + ((symbol-value 'battery-status-function) (lambda () 'fake-data))) + (should (env-laptop-p))))) + +(ert-deftest test-host-environment-laptop-p-non-linux-no-battery-char () + "Boundary: on non-Linux, an N/A char means no battery." + (let ((system-type 'darwin)) + (cl-letf (((symbol-function 'require) + (lambda (feat &rest _) (eq feat 'battery))) + ((symbol-function 'battery-format) + (lambda (_format _data) "N/A")) + ((symbol-value 'battery-status-function) (lambda () 'fake-data))) + (should-not (env-laptop-p))))) + +(ert-deftest test-host-environment-laptop-p-non-linux-no-battery-feature () + "Error: on non-Linux without the battery feature, env-laptop-p returns nil." + (let ((system-type 'darwin)) + (cl-letf (((symbol-function 'require) + (lambda (_feat &rest _) nil)) + ((symbol-value 'battery-status-function) nil)) + (should-not (env-laptop-p))))) + +;;; env-desktop-p — inverse of env-laptop-p + +(ert-deftest test-host-environment-desktop-p-true-when-not-laptop () + "Normal: env-desktop-p is t when env-laptop-p is nil." + (cl-letf (((symbol-function 'env-laptop-p) (lambda () nil))) + (should (env-desktop-p)))) + +(ert-deftest test-host-environment-desktop-p-nil-when-laptop () + "Boundary: env-desktop-p is nil when env-laptop-p is non-nil." + (cl-letf (((symbol-function 'env-laptop-p) (lambda () t))) + (should-not (env-desktop-p)))) + +(provide 'test-host-environment--env-laptop-p) +;;; test-host-environment--env-laptop-p.el ends here diff --git a/tests/test-host-environment--platform-predicates.el b/tests/test-host-environment--platform-predicates.el new file mode 100644 index 00000000..3430a939 --- /dev/null +++ b/tests/test-host-environment--platform-predicates.el @@ -0,0 +1,63 @@ +;;; test-host-environment--platform-predicates.el --- Tests for env-linux/bsd/macos/windows-p -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for the platform predicates in host-environment.el. Each is a +;; thin wrapper around `system-type'. Tests rely on `system-type' +;; being a special variable (so a `let'-binding shadows the global +;; value) and walk every supported platform to confirm the right +;; predicate returns t. + +;;; Code: + +(require 'ert) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'host-environment) + +(ert-deftest test-host-environment-linux-p-true-on-gnu-linux () + "Normal: env-linux-p returns t when system-type is gnu/linux." + (let ((system-type 'gnu/linux)) + (should (env-linux-p)))) + +(ert-deftest test-host-environment-linux-p-false-on-other-platforms () + "Boundary: env-linux-p returns nil on every non-Linux platform." + (dolist (other '(darwin berkeley-unix windows-nt cygwin ms-dos)) + (let ((system-type other)) + (should-not (env-linux-p))))) + +(ert-deftest test-host-environment-bsd-p-true-on-berkeley-unix () + "Normal: env-bsd-p returns t when system-type is berkeley-unix." + (let ((system-type 'berkeley-unix)) + (should (env-bsd-p)))) + +(ert-deftest test-host-environment-bsd-p-false-on-other-platforms () + "Boundary: env-bsd-p returns nil on every non-BSD platform." + (dolist (other '(gnu/linux darwin windows-nt cygwin ms-dos)) + (let ((system-type other)) + (should-not (env-bsd-p))))) + +(ert-deftest test-host-environment-macos-p-true-on-darwin () + "Normal: env-macos-p returns t when system-type is darwin." + (let ((system-type 'darwin)) + (should (env-macos-p)))) + +(ert-deftest test-host-environment-macos-p-false-on-other-platforms () + "Boundary: env-macos-p returns nil on every non-Darwin platform." + (dolist (other '(gnu/linux berkeley-unix windows-nt cygwin ms-dos)) + (let ((system-type other)) + (should-not (env-macos-p))))) + +(ert-deftest test-host-environment-windows-p-true-on-each-windows-variant () + "Normal: env-windows-p returns t on cygwin, windows-nt, and ms-dos." + (dolist (win '(cygwin windows-nt ms-dos)) + (let ((system-type win)) + (should (env-windows-p))))) + +(ert-deftest test-host-environment-windows-p-false-on-unix-platforms () + "Boundary: env-windows-p returns nil on Unix-family platforms." + (dolist (other '(gnu/linux darwin berkeley-unix)) + (let ((system-type other)) + (should-not (env-windows-p))))) + +(provide 'test-host-environment--platform-predicates) +;;; test-host-environment--platform-predicates.el ends here |
