ebox/tests/ebox-package-tests.el
2026-08-26 00:09:53 +08:00

257 lines
11 KiB
EmacsLisp

;;; ebox-package-tests.el --- Package contract tests -*- lexical-binding: t; -*-
(require 'cl-lib)
(require 'ert)
(defconst ebox-test--root
(expand-file-name ".." (file-name-directory (or load-file-name buffer-file-name)))
"Repository root used by package contract tests.")
(load-file (expand-file-name "ebox.el" ebox-test--root))
(defconst ebox-test--autoload-source-files
'("ebox.el"
"ebox-measure.el"
"ebox-layout.el"
"ebox-flex.el"
"ebox-grid.el"
"ebox-buffer-backend.el"
"ebox-selector.el"
"ebox-native-reflow.el")
"Source files that currently own public autoload entry points.")
(defun ebox-test--source-text ()
"Return combined source text for files that own public autoloads."
(with-temp-buffer
(dolist (file ebox-test--autoload-source-files)
(insert-file-contents (expand-file-name file ebox-test--root))
(insert "\n"))
(buffer-string)))
(ert-deftest ebox-package-defines-custom-group-and-scroll-option ()
"The package exposes a real customization group and default scroll option."
(should (get 'ebox 'custom-group))
(should (custom-variable-p 'ebox-scroll-step))
(should (integerp ebox-scroll-step))
(should (> ebox-scroll-step 0))
(should (custom-variable-p 'ebox-wheel-scroll-step))
(should (integerp ebox-wheel-scroll-step))
(should (> ebox-wheel-scroll-step 0))
(should (custom-variable-p 'ebox-wheel-smooth-scroll))
(should (custom-variable-p 'ebox-wheel-smooth-scroll-interval))
(should (numberp ebox-wheel-smooth-scroll-interval))
(should (> ebox-wheel-smooth-scroll-interval 0))
(should (custom-variable-p 'ebox-wheel-smooth-scroll-lines-per-tick))
(should (integerp ebox-wheel-smooth-scroll-lines-per-tick))
(should (> ebox-wheel-smooth-scroll-lines-per-tick 0)))
(ert-deftest ebox-facade-loads-internal-model-modules ()
"The public ebox facade should load all internal foundation modules."
(require 'ebox)
(dolist (feature '(ebox-cache ebox-style ebox-tree ebox-measure
ebox-fragment ebox-layout ebox-flex ebox-grid
ebox-buffer-backend ebox-incremental
ebox-surface ebox-viewport ebox-dsl
ebox-selector))
(should (featurep feature))))
(ert-deftest ebox-facade-exposes-native-workflow-without-loading-it ()
"The two native commands should be available without native load work."
(require 'ebox)
(should (autoloadp (symbol-function 'ebox-native-build)))
(should (autoloadp (symbol-function 'ebox-native-status)))
(should-not (featurep 'ebox-native-reflow)))
(ert-deftest ebox-byte-compile-is-an-interactive-public-command ()
"Users should be able to rebuild all active Ebox bytecode from Emacs."
(should (commandp 'ebox-byte-compile))
(should
(equal ebox--compile-sources
'("ebox-cache.el" "ebox-style.el" "ebox-child-range.el"
"ebox-tree.el" "ebox-measure.el"
"ebox-fragment.el" "ebox-render-context.el" "ebox-layout.el"
"ebox-flex.el" "ebox-grid.el" "ebox-buffer-backend.el" "ebox-incremental.el"
"ebox-native-commit.el" "ebox-surface.el" "ebox-viewport.el"
"ebox-dsl.el" "ebox-selector.el" "ebox.el"
"ebox-native-reflow.el"))))
(ert-deftest ebox-surface-depends-only-on-public-tp-api ()
"The Ebox projection boundary should never call private TP symbols."
(let ((source
(with-temp-buffer
(insert-file-contents
(expand-file-name "ebox-surface.el" ebox-test--root))
(buffer-string))))
(should-not (string-match-p "\\_<tp--" source))))
(ert-deftest ebox-css-semantics-depend-only-on-public-ecss-api ()
"Selectors and cascade must come from ECSS rather than TP or Ebox copies."
(let ((source
(with-temp-buffer
(dolist (file '("ebox-style.el" "ebox-tree.el" "ebox-selector.el"))
(insert-file-contents (expand-file-name file ebox-test--root))
(insert "\n"))
(buffer-string))))
(should-not
(string-match-p
"\\_<tp-\\(?:subject\\|selector\\|stylesheet\\|compute-style\\|computed-style\\)"
source))
(should-not (string-match-p "\\_<ecss--" source))))
(ert-deftest ebox-byte-compile-rebuilds-the-declared-source-set ()
"The interactive command should recompile every declared source in order."
(require 'bytecomp)
(let (compiled)
(unwind-protect
(cl-letf (((symbol-function 'byte-compile-file)
(lambda (file &optional _load)
(push (file-name-nondirectory file) compiled)
t))
((symbol-function 'message) #'ignore))
(should (ebox-byte-compile))
(should (equal (nreverse compiled) ebox--compile-sources)))
(when-let* ((buffer (get-buffer "*Ebox Byte Compile*")))
(kill-buffer buffer)))))
(ert-deftest ebox-package-includes-native-build-source ()
"Source-only distribution should contain every native build input."
(dolist (file '("native/Cargo.toml"
"native/Cargo.lock"
"native/build.rs"
"native/src/lib.rs"
"native/src/layout.rs"
"native/c/ebox_module.c"
"native/vendor/emacs-30/emacs-module.h"))
(should (file-readable-p (expand-file-name file ebox-test--root)))))
(ert-deftest ebox-public-entry-points-have-autoload-cookies ()
"Stable public entry points should be discoverable by package autoloads."
(let ((source (ebox-test--source-text)))
(dolist (entry '(("ebox-clear-cache" . "defun")
("ebox-render-burst-begin" . "defun")
("ebox-render-burst-end" . "defun")
("ebox-call-with-render-burst" . "defun")
("ebox-render" . "defun")
("ebox-region-ids" . "defun")
("ebox-concat" . "defun")
("ebox-spacer" . "defun")
("ebox-row" . "defun")
("ebox-stack" . "defun")
("ebox-column" . "defun")
("ebox-flex-item" . "defun")
("ebox-flex" . "defun")
("ebox-grid-fr" . "defun")
("ebox-grid-item" . "defun")
("ebox-grid" . "defun")
("ebox-build" . "defun")
("ebox-create" . "defun")
("ebox-scroll-down" . "defun")
("ebox-scroll-up" . "defun")
("ebox-region-update" . "defun")
("ebox-region-resolve" . "defun")
("ebox-buffer-update-report" . "defun")
("ebox-byte-compile" . "defun")
("ebox-native-build" . "defun")
("ebox-native-status" . "defun")
("ebox-buffer-mode" . "define-minor-mode")
("ebox-render-to-buffer" . "defun")
("ebox-display-buffer" . "defun")))
(should
(string-match-p
(format ";;;###autoload[[:space:]\n]+(%s %s\\_>"
(regexp-quote (cdr entry))
(regexp-quote (car entry)))
source)))))
(ert-deftest ebox-public-api-includes-all-public-autoloaded-entry-points ()
"The facade inventory should not omit an autoloaded public entry point."
(dolist (entry '(ebox-byte-compile
ebox-buffer-update-report
ebox-build
ebox-buffer-mode
ebox-call-with-render-burst
ebox-candidate-begin
ebox-child-range
ebox-candidate-replace
ebox-candidate-replace-range-ref
ebox-candidate-replace-root
ebox-candidate-replace-host-ref
ebox-clear-cache
ebox-column
ebox-commit
ebox-concat
ebox-create
ebox-display-buffer
ebox-display-signature
ebox-flex
ebox-flex-item
ebox-grid
ebox-grid-fr
ebox-grid-item
ebox-host-ref-bounds
ebox-host-ref-position
ebox-native-build
ebox-native-status
ebox-region-ids
ebox-region-resolve
ebox-region-update
ebox-render
ebox-render-burst-begin
ebox-render-burst-end
ebox-render-to-buffer
ebox-rerender-buffer-with-context
ebox-row
ebox-scroll-down
ebox-scroll-page-down
ebox-scroll-page-up
ebox-scroll-state
ebox-scroll-up
ebox-selector-match-node-p
ebox-selector-parse
ebox-selector-query-all
ebox-selector-query-buffer
ebox-selector-update-buffer
ebox-spacer
ebox-stack
ebox-string-pixel-width))
(should (memq entry ebox-public-api))))
(ert-deftest ebox-live-buffer-publication-uses-only-tp-surfaces ()
"The facade should expose no raw live-buffer writer beside TP surfaces."
(require 'ebox)
(dolist (entry '(ebox-render-to-buffer ebox-display-buffer))
(should (fboundp entry))
(should (memq entry ebox-public-api)))
(dolist (entry '(ebox-pop-to-buffer ebox-switch-to-buffer))
(should-not (fboundp entry))
(should-not (memq entry ebox-public-api)))
(let ((source
(with-temp-buffer
(insert-file-contents (expand-file-name "ebox.el" ebox-test--root))
(buffer-string))))
(dolist (definition '("ebox--to-buffer"
"ebox-pop-to-buffer"
"ebox-switch-to-buffer"))
(should-not
(string-match-p
(format "(defmacro[[:space:]]+%s\\_>" (regexp-quote definition))
source)))))
(ert-deftest ebox-package-exposes-buffer-report-accessor-only ()
"The package surface should expose buffer-owned reports, not a global API."
(require 'ebox)
(should (fboundp 'ebox-buffer-update-report))
(should-not (fboundp 'ebox-last-update-report))
(let ((source (ebox-test--source-text)))
(should
(string-match-p
";;;###autoload[[:space:]\n]+(defun ebox-buffer-update-report\\_>"
source))
(should-not
(string-match-p
";;;###autoload[[:space:]\n]+(defun ebox-last-update-report\\_>"
source))))
(provide 'ebox-package-tests)
;;; ebox-package-tests.el ends here