aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/test-host-environment--detect-system-timezone.el78
-rw-r--r--tests/test-host-environment--display-predicates.el112
-rw-r--r--tests/test-host-environment--env-laptop-p.el92
-rw-r--r--tests/test-host-environment--platform-predicates.el63
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